/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 * Copyright 2012 Milan Jurik. All rights reserved.
 */

#ifdef	__dilos__
#include <sys/types.h>
#include <sys/stat.h>
#endif	/* __dilos__ */

#include <libscf.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <strings.h>
#include <libstmf.h>
#include <store.h>
#include <syslog.h>
#include <signal.h>
#include <pthread.h>
#include <libnvpair.h>
#include <limits.h>
#include <unistd.h>

/*
 * This file's functions are responsible for all store and retrieve operations
 * against the STMF smf(7) database. The following shows the currently defined
 * schema for the STMF database:
 *
 * Description of property groups for service: svc:/system/stmf
 *
 * Stability: Volatile
 *
 * 1. Property Group: host_groups
 *        Properties: group_name-<N> where <N> is an unsigned integer
 *                        type: ustring
 *                        contains: group name
 *                    group_name-<N>-member_list where <N> is an unsigned
 *                            integer matching a group_name-<N> property.
 *                        type: ustring
 *                        contains: list of members
 *
 *        Description:
 *             Contains the host group names as well as the host group members
 *             for each host group.
 *
 * 2. Property Group: target_groups
 *        Properties: group_name-<N> where <N> is an unsigned integer
 *                        type: ustring
 *                        contains: group name
 *                    group_name-<N>-member_list where <N> is an unsigned
 *                            integer matching a group_name-<N> property.
 *                        type: ustring
 *                        contains: list of members
 *
 *        Description:
 *             Contains the target group names as well as the target group
 *             members for each target group.
 *
 * 3. Property Group: lu-<GUID>
 *                        where <GUID> is a 32 character hexadecimal string.
 *        Properties: ve_cnt
 *                        type: count
 *                        contains: the number of current view entries
 *                    view-entry-<N>-<GUID> where <N> is an unsigned integer
 *                        type: ustring
 *                        contains: nothing. Used as reference to the view
 *                                  entry property group
 *
 *        Description:
 *             Contains the references to each view entry. One lu-<GUID>
 *             property group will exist for each logical unit with 1 or more
 *             view entries.
 *             Potentially can hold any other data that can be managed on a per
 *             logical unit basis.
 *
 * 4. Property Group: view_entry-<N>-<GUID> (matches property in lu-<GUID>
 *                    property group)
 *        Properties: all_hosts
 *                        type: boolean
 *                        contains: when true, the value of host_group is
 *                                  ignored
 *                    all_targets
 *                        type: boolean
 *                        contains: when true, the value of target_group is
 *                                  ignored
 *                    host_group
 *                        type: ustring
 *                        contains: host group for logical unit mapping and
 *                                  masking purposes
 *                    target_group
 *                        type: ustring
 *                        contains: target group for logical unit mapping and
 *                                  masking purposes
 *                    lu_nbr
 *                        type: opaque
 *                        contains: the 8-byte SCSI logical unit number for
 *                                  mapping and masking purposes
 *        Description:
 *             One "view_entry-<N>-<GUID>" property group will exist for each
 *             view entry in the system. This property group name maps
 *             directly to the "lu-<GUID>" property group with a matching
 *             <GUID>.
 *
 * 5. Property Group: provider_data_pg_<provider-name>
 *                        where <provider-name> is the name of the provider
 *                           registered with stmf.
 *        Properties: provider_data_prop-<N>
 *                        where <N> is a sequential identifier for the data
 *                           chunk.
 *                        type: opaque
 *                        contains: up to STMF_PROVIDER_DATA_PROP_SIZE bytes
 *                                  of nvlist packed data.
 *                    provider_data_count
 *                        type: count
 *                        contains: the number of provider data chunks
 *                    provider_data_type
 *                        type: integer
 *                        contains: STMF_PORT_PROVIDER_TYPE or
 *                                  STMF_LU_PROVIDER_TYPE
 *
 *        Description:
 *             Holds the nvlist packed provider data set via
 *             stmfSetProviderData and retrieved via stmfGetProviderData. Data
 *             is stored in STMF_PROVIDER_DATA_PROP_SIZE chunks. On retrieve,
 *             these chunks are reassembled and unpacked.
 *
 */

static int iPsInit(scf_handle_t **, scf_service_t **);
static int iPsCreateDeleteGroup(char *, char *, int);
static int iPsAddRemoveGroupMember(char *, char *, char *, int);
static int iPsGetGroupList(char *, stmfGroupList **);
static int iPsGetGroupMemberList(char *, char *, stmfGroupProperties **);
static int iPsAddViewEntry(char *, char *, stmfViewEntry *);
static int iPsAddRemoveLuViewEntry(char *, char *, int);
static int iPsGetViewEntry(char *, stmfViewEntry *);
static int iPsGetActualGroupName(char *, char *, char *);
static int iPsGetServiceVersion(uint64_t *, scf_handle_t *, scf_service_t *);
static int iPsGetSetPersistType(uint8_t *, scf_handle_t *, scf_service_t *, int);
static int iPsGetSetStmfProp(int, char *, int);
static int viewEntryCompare(const void *, const void *);
static int holdSignal(sigset_t *);
static int releaseSignal(sigset_t *);
static void sigHandler();
static int iPsClearGroups(char *pgRefName);

static pthread_mutex_t sigSetLock = PTHREAD_MUTEX_INITIALIZER;

sigset_t sigSet;
sigset_t signalsCaught;

struct sigaction currentActionQuit;
struct sigaction currentActionTerm;
struct sigaction currentActionInt;

boolean_t actionSet = B_FALSE;

/*
 * Version info for the SMF schema
 */
#define	STMF_SMF_VERSION    1

/*
 * Note: Do not change these property names and size values.
 * They represent fields in the persistent config and once modified
 * will have a nasty side effect of invalidating the existing store.
 * If you do need to change them, you'll need to use the versioning above
 * to retain backward compatiblity with the previous configuration schema.
 */

/* BEGIN STORE PROPERTY DEFINITIONS */
/*
 * Property Group Names and prefixes
 */
#define	STMF_HOST_GROUPS	"host_groups"
#define	STMF_TARGET_GROUPS	"target_groups"
#define	STMF_VE_PREFIX		"view_entry"
#define	STMF_LU_PREFIX		"lu"
#define	STMF_DATA_GROUP		"stmf_data"

/*
 * Property names and prefix for logical unit property group
 */
#define	STMF_VE_CNT		"ve_cnt"
#define	STMF_GROUP_PREFIX	"group_name"
#define	STMF_MEMBER_LIST_SUFFIX	"member_list"
#define	STMF_VERSION_NAME	"version_name"
#define	STMF_PERSIST_TYPE	"persist_method"

/* Property names for stmf properties */

#define	DEFAULT_LU_STATE		"default_lu_state"
#define	DEFAULT_TARGET_PORT_STATE	"default_target_state"

/*
 * Property names for view entry
 */
#define	STMF_VE_ALLHOSTS	    "all_hosts"
#define	STMF_VE_HOSTGROUP	    "host_group"
#define	STMF_VE_ALLTARGETS	    "all_targets"
#define	STMF_VE_TARGETGROUP	    "target_group"
#define	STMF_VE_LUNBR		    "lu_nbr"

/* Property group suffix for provider data */
#define	STMF_PROVIDER_DATA_PREFIX "provider_data_pg_"
#define	STMF_PROVIDER_DATA_PROP_PREFIX "provider_data_prop"
#define	STMF_PROVIDER_DATA_PROP_NAME_SIZE 256
#define	STMF_PROVIDER_DATA_PROP_TYPE "provider_type"
#define	STMF_PROVIDER_DATA_PROP_SET_COUNT "provider_data_set_cnt"
#define	STMF_PROVIDER_DATA_PROP_COUNT "provider_data_cnt"


#define	STMF_SMF_READ_ATTR	"solaris.smf.read.stmf"

#define	STMF_PS_PERSIST_NONE	"none"
#define	STMF_PS_PERSIST_SMF	"smf"
#define	STMF_PROVIDER_DATA_PROP_SIZE 4000

#define	STMF_PS_LU_ONLINE		"default_lu_online"
#define	STMF_PS_LU_OFFLINE		"default_lu_offline"
#define	STMF_PS_TARGET_PORT_ONLINE	"default_target_online"
#define	STMF_PS_TARGET_PORT_OFFLINE	"default_target_offline"

/* END STORE PROPERTY DEFINITIONS */

/* service name */
#define	STMF_SERVICE	"system/stmf"

/* limits and flag values */
#define	GROUP_MEMBER_ALLOC 100
#define	VIEW_ENTRY_STRUCT_CNT 6
#define	VIEW_ENTRY_PG_SIZE 256
#define	LOGICAL_UNIT_PG_SIZE 256
#define	VIEW_ENTRY_MAX UINT32_MAX
#define	GROUP_MAX UINT64_MAX
#define	ADD 0
#define	REMOVE 1
#define	GET 0
#define	SET 1
#define GUID_STRING_LENGTH 34

/***************** EXTENDED MODE FUNCTIONS ****************************/
#define LU_PROP_NAME_FILE        "file"
#define LU_PROP_NAME_PROVIDER    "provider"
#define LU_PROP_NAME_PROPERTIES  "diskprops"
#define LU_PROP_NAME_VECOUNT     "vecount"
#define LU_PROP_NAME_VELIST      "velist"

#define VE_PROP_NAME_INDEX       "veIndex"
#define VE_PROP_NAME_ALLHOSTS    "allHosts"
#define VE_PROP_NAME_HOSTGROUP   "hostGroup"
#define VE_PROP_NAME_ALLTARGETS  "allTargets"
#define VE_PROP_NAME_TARGETGROUP "targetGroup"
#define VE_PROP_NAME_LUNUMBER    "luNbr"

static int iPsAddGroupMemberExt(char *pgName, char *groupName,
                                char *memberName);
static int iPsRemoveGroupMemberExt(char *pgName, char *groupName,
                                   char *memberName);
static int iPsGetGroupMemberListExt(char *pgName, char *groupName,
                                    stmfGroupProperties **groupMemberList);

static int iPsAddViewEntryExt(stmfGuid *lu, stmfViewEntry *viewEntry);
static int iPsGetViewEntryExt(stmfGuid *lu, uint32_t viewEntryIndex,
                              stmfViewEntry *viewEntry);
static int iPsRemoveViewEntryExt(stmfGuid *lu, uint32_t viewEntryIndex);
static int iPsGetViewEntryListExt(stmfGuid *lu, nvlist_t **nvl, uint64_t *veCnt);

static int iPsClearGroupsExt(char *pgName);
static int iPsCreateGroupExt(char *pgName, char *groupName);
static int iPsDeleteGroupExt(char *pgName, char *groupName);
static int iPsGetActualGroupNameExt(char *pgName, char *groupName,
                                    char *groupPropName);
static int iPsGetGroupListExt(char *pgName, stmfGroupList **groupList);

static int iPsFromNvlToStmfLuListExt(nvlist_t nvl, stmfGuidList *guidList,
                                     uint64_t guidCnt);
static int iPsFromNvlToStmfVeListExt(nvlist_t nvl,
                                     stmfViewEntryList *viewEntryList,
                                     uint64_t veCnt);

static int iPsGetLogicalUnitListExt(nvlist_t **nvl, int *guidCnt);
static int iPsGetProviderDataExt(char *providerName, nvlist_t **nvl,
                                 int providerType, uint64_t *setToken);
static int iPsSetProviderDataExt(char *providerName, nvlist_t *nvl,
                                 int providerType, uint64_t *setToken);
static int iPsGetProviderDataListExt(stmfProviderList **providerList);

/* These functions concern STMF service state. Do we have to save it? Seems no.
static int iPsGetStmfPropExt(int propType, char *propVal);
static int iPsSetStmfPropExt(int propType, char *propVal);
*/

static int iPsLoadConfigExt(void);
static int iPsSaveConfigExt(void);
static void iPsFreeConfigExt(void);

static int iPsClearListMembersExt(nvlist_t *parent);
static boolean_t iPsGuidToString(stmfGuid lu, char *string);
static boolean_t iPsStringToGuid(char *string, stmfGuid *lu);

static int convertDiskPropsToNvl(diskResource *lu, nvlist_t *luList);
static int convertDiskPropsFromNvl(nvlist_t *luList, diskResource *lu);
static int convertViewEntryToNvl(stmfViewEntry *viewEntry, nvlist_t *veList);
static int convertViewEntryFromNvl(nvlist_t *veList, stmfViewEntry *viewEntry);

/* when B_TRUE, STMF will not write LU information to the DataBase */
static boolean_t iPsExtendedMode = B_FALSE;
static char      iPsExternalStorage[256] = "";
static nvlist_t *iPsConfig = NULL;
/* LU Properties names */
static char diskProps[STMF_LU_PROP_HOST_ID][10] = {
    "alias", "blk", "oui", "file", "guid", "meta", "mgmt-url", "new",
    "size", "wp", "wcd", "vid", "pid", "serial", "access", "host-id"
};

FILE *lgstmf = NULL;

int psSetExternalStorage(const char *pEnv)
{
    if( pEnv == NULL )
        strcpy(iPsExternalStorage, "");
    else
        strncpy(iPsExternalStorage, pEnv, 256);
    return iPsLoadConfigExt();
}

void psSetExtendedMode(boolean_t mode)
{
    iPsExtendedMode = mode;
}

boolean_t psGetExtendedMode(void)
{
    return iPsExtendedMode;
}

int psSaveConfigExt(void)
{
    return iPsSaveConfigExt();
}

static int convertViewEntryToNvl(stmfViewEntry *ve, nvlist_t *veProps)
{
    int ret = 0;

    if ((veProps == NULL) || (ve == NULL)) {
        return STMF_STATUS_ERROR;
    }
    if (ve->veIndexValid == B_TRUE) {
        ret += nvlist_add_uint32(veProps, VE_PROP_NAME_INDEX, ve->veIndex);
    }
    ret += nvlist_add_boolean_value(veProps, VE_PROP_NAME_ALLHOSTS,
                                    ve->allHosts);
    ret += nvlist_add_string(veProps, VE_PROP_NAME_HOSTGROUP, ve->hostGroup);
    ret += nvlist_add_boolean_value(veProps, VE_PROP_NAME_ALLTARGETS,
                                    ve->allTargets);
    ret += nvlist_add_string(veProps, VE_PROP_NAME_TARGETGROUP, ve->targetGroup);
    if (ve->luNbrValid == B_TRUE) {
        ret += nvlist_add_byte_array(veProps, VE_PROP_NAME_LUNUMBER,
                                     ve->luNbr, 8);
    }

    if (ret == 0) {
        return STMF_STATUS_SUCCESS;
    }
    syslog(LOG_ERR, "can't convert stmfViewEntry to nvlist - %i properties were"
                    " not added", ret);
    return STMF_STATUS_ERROR;
}

static int convertViewEntryFromNvl(nvlist_t *veProps, stmfViewEntry *ve)
{
    int ret = 0;
    uint_t tmp = 0;
    char *st = NULL;
    uchar_t *ba = NULL;

    if ((veProps == NULL) || (ve == NULL)) {
        return STMF_STATUS_ERROR;
    }
    ve->veIndexValid = nvlist_exists(veProps, VE_PROP_NAME_INDEX);
    if (ve->veIndexValid == B_TRUE) {
        ret += nvlist_lookup_uint32(veProps, VE_PROP_NAME_INDEX, &(ve->veIndex));
    }
    ve->luNbrValid = nvlist_exists(veProps, VE_PROP_NAME_LUNUMBER);
    if (ve->luNbrValid == B_TRUE) {
        ret += nvlist_lookup_byte_array(veProps, VE_PROP_NAME_LUNUMBER, &ba, &tmp);
        if (ba != NULL) {
            bcopy(ba, ve->luNbr, tmp);
        }
    }
    if (B_TRUE == nvlist_exists(veProps, VE_PROP_NAME_ALLHOSTS)) {
        ret += nvlist_lookup_boolean_value(veProps, VE_PROP_NAME_ALLHOSTS,
                                           &(ve->allHosts));
    }
    if (B_TRUE == nvlist_exists(veProps, VE_PROP_NAME_HOSTGROUP)) {
        ret += nvlist_lookup_string(veProps, VE_PROP_NAME_HOSTGROUP, &st);
        if (st != NULL) {
            strcpy(ve->hostGroup, st);
        }
    }
    if (B_TRUE == nvlist_exists(veProps, VE_PROP_NAME_ALLTARGETS)) {
        ret += nvlist_lookup_boolean_value(veProps, VE_PROP_NAME_ALLTARGETS,
                                           &(ve->allTargets));
    }
    if (B_TRUE == nvlist_exists(veProps, VE_PROP_NAME_TARGETGROUP)) {
        ret += nvlist_lookup_string(veProps, VE_PROP_NAME_TARGETGROUP, &st);
        if (st != NULL) {
            strcpy(ve->hostGroup, st);
        }
    }

    if (ret == 0) {
        return STMF_STATUS_SUCCESS;
    }
    syslog(LOG_ERR, "can't convert nvlist to stmfViewEntry - %i properties were"
                    " not converted", ret);
    return  STMF_STATUS_ERROR;
}

static int convertDiskPropsToNvl(diskResource *lu, nvlist_t *luProps)
{
    int ret = 0;

    if ((luProps == NULL) || (lu == NULL)) {
        return STMF_STATUS_ERROR;
    }
    if (lu->luDataFileNameValid == B_TRUE) {
        ret += nvlist_add_string(luProps, diskProps[STMF_LU_PROP_FILENAME-1],
                                 lu->luDataFileName);
    }
    if (lu->luMetaFileNameValid == B_TRUE) {
        ret += nvlist_add_string(luProps,
                                 diskProps[STMF_LU_PROP_META_FILENAME-1],
                                 lu->luMetaFileName);
    }
    if (lu->luSizeValid == B_TRUE) {
        ret += nvlist_add_uint64(luProps, diskProps[STMF_LU_PROP_SIZE-1],
                                 lu->luSize);
    }
    if (lu->blkSizeValid == B_TRUE) {
        ret += nvlist_add_uint16(luProps, diskProps[STMF_LU_PROP_BLOCK_SIZE-1],
                                 lu->blkSize);
    }
    if (lu->luGuidValid == B_TRUE) {
        ret += nvlist_add_uint8_array(luProps, diskProps[STMF_LU_PROP_GUID-1],
                                      lu->luGuid, 16);
    }
    if (lu->serialNumValid == B_TRUE) {
        ret += nvlist_add_string(luProps, diskProps[STMF_LU_PROP_SERIAL_NUM-1],
                                 lu->serialNum);
    }
    if (lu->companyIdValid == B_TRUE) {
        ret += nvlist_add_uint32(luProps, diskProps[STMF_LU_PROP_COMPANY_ID-1],
                                 lu->companyId);
    }
    if (lu->luAliasValid == B_TRUE) {
        ret += nvlist_add_string(luProps, diskProps[STMF_LU_PROP_ALIAS-1],
                                 lu->luAlias);
    }
    if (lu->luMgmtUrlValid == B_TRUE) {
        ret += nvlist_add_string(luProps, diskProps[STMF_LU_PROP_MGMT_URL-1],
                                 lu->luMgmtUrl);
    }
    if (lu->vidValid == B_TRUE) {
        ret += nvlist_add_string(luProps, diskProps[STMF_LU_PROP_VID-1],
                                 lu->vid);
    }
    if (lu->pidValid == B_TRUE) {
        ret += nvlist_add_string(luProps, diskProps[STMF_LU_PROP_PID-1],
                                 lu->pid);
    }
    if (lu->revValid == B_TRUE) {
        ret += nvlist_add_string(luProps, diskProps[STMF_LU_PROP_NEW-1],
                                 lu->rev);
    }
    if (lu->writeProtectEnableValid == B_TRUE) {
        ret += nvlist_add_boolean_value(luProps,
                                        diskProps[STMF_LU_PROP_WRITE_PROTECT-1],
                                        lu->writeProtectEnable);
    }
    if (lu->writebackCacheDisableValid == B_TRUE) {
        ret += nvlist_add_boolean_value(luProps,
                                  diskProps[STMF_LU_PROP_WRITE_CACHE_DISABLE-1],
                                        lu->writebackCacheDisable);
    }
    ret += nvlist_add_uint16(luProps, diskProps[STMF_LU_PROP_ACCESS_STATE-1],
                             lu->accessState);
    if (lu->hostIdValid == B_TRUE) {
        ret += nvlist_add_uint32(luProps, diskProps[STMF_LU_PROP_HOST_ID-1],
                                 lu->hostId);
    }

    if (ret == 0) {
        return STMF_STATUS_SUCCESS;
    }
    syslog(LOG_ERR, "can't convert diskResource to nvlist - %i properties were"
                    " not added", ret);
    return STMF_STATUS_ERROR;
}

static int convertDiskPropsFromNvl(nvlist_t *luList, diskResource *lu)
{
    int ret = 0;
    uint_t tmp = 0;
    char *st = NULL;
    uint8_t *ia = NULL;

    if ((luList == NULL) || (lu == NULL)) {
        return STMF_STATUS_ERROR;
    }
    lu->luDataFileNameValid = nvlist_exists(luList,
                                            diskProps[STMF_LU_PROP_FILENAME-1]);
    if (lu->luDataFileNameValid == B_TRUE) {
        ret += nvlist_lookup_string(luList, diskProps[STMF_LU_PROP_FILENAME-1], &st);
        if (st != NULL) {
            strcpy(lu->luDataFileName, st);
        }
    }
    lu->luMetaFileNameValid = nvlist_exists(luList,
                                        diskProps[STMF_LU_PROP_META_FILENAME-1]);
    if (lu->luMetaFileNameValid == B_TRUE) {
        ret += nvlist_lookup_string(luList,
                                    diskProps[STMF_LU_PROP_META_FILENAME-1], &st);
        if (st != NULL) {
            strcpy(lu->luMetaFileName, st);
        }
    }
    lu-> luSizeValid = nvlist_exists(luList, diskProps[STMF_LU_PROP_SIZE-1]);
    if (lu->luSizeValid == B_TRUE) {
        ret += nvlist_lookup_uint64(luList, diskProps[STMF_LU_PROP_SIZE-1],
                                    &(lu->luSize));
    }
    lu->blkSizeValid = nvlist_exists(luList,
                                     diskProps[STMF_LU_PROP_BLOCK_SIZE-1]);
    if (lu->blkSizeValid == B_TRUE) {
        ret += nvlist_lookup_uint16(luList, diskProps[STMF_LU_PROP_BLOCK_SIZE-1],
                                    &(lu->blkSize));
    }
    lu->luGuidValid = nvlist_exists(luList, diskProps[STMF_LU_PROP_GUID-1]);
    if (lu->luGuidValid == B_TRUE) {
        ret += nvlist_lookup_uint8_array(luList, diskProps[STMF_LU_PROP_GUID-1],
                                         &ia, &tmp);
        if (ia != NULL) {
            bcopy(ia, lu->luGuid, tmp);
        }
    }
    lu->serialNumValid = nvlist_exists(luList,
                                       diskProps[STMF_LU_PROP_SERIAL_NUM-1]);
    if (lu->serialNumValid == B_TRUE) {
        ret += nvlist_lookup_string(luList,
                                    diskProps[STMF_LU_PROP_SERIAL_NUM-1], &st);
        if (st != NULL) {
        strcpy(lu->serialNum, st);
        }
    }
    lu->companyIdValid = nvlist_exists(luList,
                                       diskProps[STMF_LU_PROP_COMPANY_ID-1]);
    if (lu->companyIdValid == B_TRUE) {
        ret += nvlist_lookup_uint32(luList, diskProps[STMF_LU_PROP_COMPANY_ID-1],
                                    &(lu->companyId));
    }
    lu->luAliasValid = nvlist_exists(luList, diskProps[STMF_LU_PROP_ALIAS-1]);
    if (lu->luAliasValid == B_TRUE) {
        ret += nvlist_lookup_string(luList, diskProps[STMF_LU_PROP_ALIAS-1], &st);
        if (st != NULL) {
            strcpy(lu->luAlias, st);
        }
    }
    lu->luMgmtUrlValid = nvlist_exists(luList,
                                       diskProps[STMF_LU_PROP_MGMT_URL-1]);
    if (lu->luMgmtUrlValid == B_TRUE) {
        ret += nvlist_lookup_string(luList,
                                    diskProps[STMF_LU_PROP_MGMT_URL-1], &st);
        if (st != NULL) {
            strcpy(lu->luMgmtUrl, st);
        }
    }
    lu->vidValid = nvlist_exists(luList, diskProps[STMF_LU_PROP_VID-1]);
    if (lu->vidValid == B_TRUE) {
        ret += nvlist_lookup_string(luList, diskProps[STMF_LU_PROP_VID-1], &st);
        if (st != NULL) {
            strcpy(lu->vid, st);
        }
    }
    lu->pidValid = nvlist_exists(luList, diskProps[STMF_LU_PROP_PID-1]);
    if (lu->pidValid == B_TRUE) {
        ret += nvlist_lookup_string(luList, diskProps[STMF_LU_PROP_PID-1], &st);
        if (st != NULL) {
            strcpy(lu->pid, st);
        }
    }
    lu->revValid = nvlist_exists(luList, diskProps[STMF_LU_PROP_NEW-1]);
    if (lu->revValid == B_TRUE) {
        ret += nvlist_lookup_string(luList, diskProps[STMF_LU_PROP_NEW-1], &st);
        if (st != NULL) {
            strcpy(lu->rev, st);
        }
    }
    lu->writeProtectEnableValid = nvlist_exists(luList,
                                        diskProps[STMF_LU_PROP_WRITE_PROTECT-1]);
    if (lu->writeProtectEnableValid == B_TRUE) {
        ret += nvlist_lookup_boolean_value(luList,
                                        diskProps[STMF_LU_PROP_WRITE_PROTECT-1],
                                           &(lu->writeProtectEnable));
    }
    lu->writebackCacheDisableValid = nvlist_exists(luList,
                                  diskProps[STMF_LU_PROP_WRITE_CACHE_DISABLE-1]);
    if (lu->writebackCacheDisableValid == B_TRUE) {
        ret += nvlist_lookup_boolean_value(luList,
                                   diskProps[STMF_LU_PROP_WRITE_CACHE_DISABLE-1],
                                           &(lu->writebackCacheDisable));
    }
    ret += nvlist_lookup_uint16(luList, diskProps[STMF_LU_PROP_ACCESS_STATE-1],
                                &(lu->accessState));
    lu->hostIdValid = nvlist_exists(luList, diskProps[STMF_LU_PROP_HOST_ID-1]);
    if (lu->hostIdValid == B_TRUE) {
        ret += nvlist_lookup_uint32(luList, diskProps[STMF_LU_PROP_HOST_ID-1],
                                    &(lu->hostId));
    }

    if (ret == 0) {
        return STMF_STATUS_SUCCESS;
    }
    syslog(LOG_ERR, "can't convert nvlist to diskResource - %i properties were"
                    " not converted", ret);
    return STMF_STATUS_ERROR;
}

static boolean_t iPsGuidToString(stmfGuid lu, char *string)
{
    if (string == NULL)
        return B_FALSE;
    /* Convert to ASCII uppercase hexadecimal string */
    (void) snprintf(string, GUID_STRING_LENGTH,
             "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
                    lu.guid[0], lu.guid[1], lu.guid[2], lu.guid[3], lu.guid[4],
                    lu.guid[5], lu.guid[6], lu.guid[7], lu.guid[8], lu.guid[9],
                    lu.guid[10], lu.guid[11], lu.guid[12], lu.guid[13],
                    lu.guid[14], lu.guid[15]);
    return B_TRUE;
}

static boolean_t iPsStringToGuid(char *string, stmfGuid *lu)
{
    if ((string == NULL) || (lu == NULL))
        return B_FALSE;
    (void) sscanf(string, "%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X",
                  &lu->guid[0], &lu->guid[1], &lu->guid[2], &lu->guid[3],
                  &lu->guid[4], &lu->guid[5], &lu->guid[6], &lu->guid[7],
                  &lu->guid[8], &lu->guid[9], &lu->guid[10],&lu->guid[11],
                  &lu->guid[12], &lu->guid[13], &lu->guid[14], &lu->guid[15]);
    return B_TRUE;
}

int iPsCountPairs(nvlist_t *list)
{
    int memberCnt = 0;
    nvpair_t *nvp = NULL;

    nvp = nvlist_next_nvpair(list, NULL);
    while (nvp != NULL) {
        nvp = nvlist_next_nvpair(list, nvp);
        memberCnt++;
    }
    return memberCnt;
}

void __prt_nvlist(nvlist_t *parent)
{
    int cnt = 0;
    nvpair_t *curr = NULL, *nvp = NULL;
    nvlist_t *nvl = NULL;
    char tp[32] = "", vl[256] = "", *st = NULL;
    boolean_t bl;
    uchar_t bt;
    int8_t i8;
    uint8_t u8;
    int16_t i16;
    uint16_t u16;

    STMFLOG(lgstmf, "\nNVL[%p]: **********************> 1 : ENTER\n", parent);
    curr = nvlist_next_nvpair(parent, NULL);
    while (curr != NULL) {
        cnt++;
        nvp = nvlist_next_nvpair(parent, curr);
        switch((int)nvpair_type(curr)) {
        case DATA_TYPE_BOOLEAN:
            strcpy(tp, "DATA_TYPE_BOOLEAN");
            break;
        case DATA_TYPE_BOOLEAN_VALUE:
            strcpy(tp, "DATA_TYPE_BOOLEAN_VALUE");
            nvpair_value_boolean_value(curr, &bl);
            strcpy(vl, (B_TRUE == bl)?"B_TRUE":"B_FALSE");
            break;
        case DATA_TYPE_BYTE:
            strcpy(tp, "DATA_TYPE_BYTE");
            nvpair_value_byte(curr, &bt);
            sprintf(vl, "0x%02X", bt);
            break;
        case DATA_TYPE_INT8:
            strcpy(tp, "DATA_TYPE_INT8");
            nvpair_value_int8(curr, &i8);
            sprintf(vl, "%i",i8);
            break;
        case DATA_TYPE_UINT8:
            strcpy(tp, "DATA_TYPE_UINT8");
            nvpair_value_uint8(curr, &u8);
            sprintf(vl, "%u", u8);
            break;
        case DATA_TYPE_INT16:
            strcpy(tp, "DATA_TYPE_INT16");
            nvpair_value_int16(curr, &i16);
            sprintf(vl, "%i", i16);
            break;
        case DATA_TYPE_UINT16:
            strcpy(tp, "DATA_TYPE_UINT16");
            nvpair_value_uint16(curr, &u16);
            sprintf(vl, "%u", u16);
            break;
        case DATA_TYPE_INT32:
            strcpy(tp, "DATA_TYPE_INT32");
            break;
        case DATA_TYPE_UINT32:
            strcpy(tp, "DATA_TYPE_UINT32");
            break;
        case DATA_TYPE_INT64:
            strcpy(tp, "DATA_TYPE_INT64");
            break;
        case DATA_TYPE_UINT64:
            strcpy(tp, "DATA_TYPE_UINT64");
            break;
        case DATA_TYPE_STRING:
            strcpy(tp, "DATA_TYPE_STRING");
            nvpair_value_string(curr, &st);
            if (st != NULL)
               strcpy(vl, st);
            break;
        case DATA_TYPE_NVLIST:
            strcpy(tp, "DATA_TYPE_NVLIST");
            break;
        case DATA_TYPE_BOOLEAN_ARRAY:
            strcpy(tp, "DATA_TYPE_BOOLEAN_ARRAY");
            break;
        case DATA_TYPE_BYTE_ARRAY:
            strcpy(tp, "DATA_TYPE_BYTE_ARRAY");
            break;
        case DATA_TYPE_INT8_ARRAY:
            strcpy(tp, "DATA_TYPE_INT8_ARRAY");
            break;
        case DATA_TYPE_UINT8_ARRAY:
            strcpy(tp, "DATA_TYPE_UINT8_ARRAY");
            break;
        case DATA_TYPE_INT16_ARRAY:
            strcpy(tp, "DATA_TYPE_INT16_ARRAY");
            break;
        case DATA_TYPE_UINT16_ARRAY:
            strcpy(tp, "DATA_TYPE_UINT16_ARRAY");
            break;
        case DATA_TYPE_INT32_ARRAY:
            strcpy(tp, "DATA_TYPE_INT32_ARRAY");
            break;
        case DATA_TYPE_UINT32_ARRAY:
            strcpy(tp, "DATA_TYPE_UINT32_ARRAY");
            break;
        case DATA_TYPE_INT64_ARRAY:
            strcpy(tp, "DATA_TYPE_INT64_ARRAY");
            break;
        case DATA_TYPE_UINT64_ARRAY:
            strcpy(tp, "DATA_TYPE_UINT64_ARRAY");
            break;
        case DATA_TYPE_STRING_ARRAY:
            strcpy(tp, "DATA_TYPE_STRING_ARRAY");
            break;
        case DATA_TYPE_NVLIST_ARRAY:
            strcpy(tp, "DATA_TYPE_NVLIST_ARRAY");
            break;
        }
        STMFLOG(lgstmf, "NVL[%p]: **********************> 2[%i] : %s(%s)\n",
                parent, cnt, nvpair_name(curr), tp);
        if (DATA_TYPE_NVLIST == nvpair_type(curr)) {
            nvpair_value_nvlist(curr, &nvl);
            __prt_nvlist(nvl);
        }
        curr = nvp;
    }
    STMFLOG(lgstmf, "NVL[%p]: **********************> 3 : EXIT [%i]\n", parent, cnt);
}

static int iPsClearListMembersExt(nvlist_t *parent)
{
    int ret = 0;
    nvpair_t *curr = NULL, *nvp = NULL;
    nvlist_t *nvl = NULL;

    curr = nvlist_next_nvpair(parent, NULL);
    while (curr != NULL) {
        nvp = nvlist_next_nvpair(parent, curr);
        if (DATA_TYPE_NVLIST == nvpair_type(curr)) {
            nvpair_value_nvlist(curr, &nvl);
            ret += iPsClearListMembersExt(nvl);
            ret += nvlist_remove(parent, nvpair_name(curr), nvpair_type(curr));
            if (nvl != NULL) {
                nvlist_free(nvl);
                nvl = NULL;
            }
        }
        else {
            ret += nvlist_remove(parent, nvpair_name(curr), nvpair_type(curr));
        }
        curr = nvp;
    }
    return ret;
}

int iPsFindLuExt(stmfGuid *guid, nvlist_t **lu)
{
    nvlist_t *nvl = NULL;
    char luName[GUID_STRING_LENGTH] = "";

    if (iPsExtendedMode == B_FALSE) {
        return STMF_PS_ERROR;
    }
    if ((guid == NULL) || (lu == NULL)) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    *lu = NULL;
    if (iPsConfig == NULL) {
        syslog(LOG_ERR, "can't find logical unit - extended configuration"
                        " is not loaded");
        return STMF_PS_ERROR;
    }
    if (0 != nvlist_lookup_nvlist(iPsConfig, "LU", &nvl)) {
        syslog(LOG_ERR, "can't find logical unit - logical unit list doesn't"
                        " exist");
        return STMF_PS_ERROR_NOT_FOUND;
    }
    iPsGuidToString(*guid, luName);
    /* find LU in the list */
    if (0 != nvlist_lookup_nvlist(nvl, luName, lu)) {
        return STMF_PS_ERROR_NOT_FOUND;
    }
    return STMF_STATUS_SUCCESS;
}

int psStoreDiskProperties(stmfGuid *guid, diskResource *disk)
{
    nvlist_t *luProps = NULL, *lu = NULL;
    int ret = STMF_PS_ERROR;

    if (iPsExtendedMode == B_FALSE) {
        return STMF_STATUS_SUCCESS;
    }
    if ((guid == NULL) || (disk == NULL)) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    ret = iPsFindLuExt(guid, &lu);
    if (ret != STMF_STATUS_SUCCESS) {
        return ret;
    }
    /* check "diskprop" list in lu information */
    if (B_TRUE == nvlist_exists(lu, LU_PROP_NAME_PROPERTIES)) {
        /* it exists, remove */
        if (0 != nvlist_remove(lu, LU_PROP_NAME_PROPERTIES, DATA_TYPE_NVLIST)) {
            syslog(LOG_ERR, "can't store disk properties - old section is not"
                            " removed");
            return STMF_PS_ERROR;
        }
    }
    /* allocate memory for "diskprop" list */
    if (0 != nvlist_alloc(&luProps, NV_UNIQUE_NAME, 0)) {
        syslog(LOG_ERR, "can't store disk properties - not enough memory");
        return STMF_PS_ERROR_NOMEM;
    }
    /* convert LU properties from diskResource to nvlist */
    if (STMF_STATUS_SUCCESS != convertDiskPropsToNvl(disk, luProps)) {
        syslog(LOG_ERR, "can't store disk properties - error converting from"
                        " diskResource to nvlist");
        nvlist_free(luProps);
        return STMF_PS_ERROR;
    }
    /* add "diskprop" list to lu information */ 
    if (0 == nvlist_add_nvlist(lu, LU_PROP_NAME_PROPERTIES, luProps)) {
        /* save config */
        ret = iPsSaveConfigExt();
    }
    if (ret != STMF_STATUS_SUCCESS) {
        syslog(LOG_ERR, "can't store disk properties - add nvlist error");
        nvlist_free(luProps);
    }
    return ret;
}

int psReStoreDiskProperties(stmfGuid *guid, diskResource *disk)
{
    nvlist_t *luProps = NULL, *lu = NULL;
    int ret = STMF_PS_ERROR;

    if (iPsExtendedMode == B_FALSE) {
        return STMF_STATUS_SUCCESS;
    }
    if ((guid == NULL) || (disk == NULL)) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    ret = iPsFindLuExt(guid, &lu);
    if (ret != STMF_STATUS_SUCCESS) {
        return ret;
    }
    /* check "diskprop" list in lu information */
    if (0 == nvlist_lookup_nvlist(lu, LU_PROP_NAME_PROPERTIES, &luProps)) {
        /* convert LU properties from diskResource to nvlist */
        if (STMF_STATUS_SUCCESS != convertDiskPropsFromNvl(luProps, disk)) {
            return STMF_PS_ERROR;
        }
    }
    return STMF_STATUS_SUCCESS;
}

static int iPsAddGroupMemberExt(char *pgName, char *groupName, char *memberName)
{
    int ret = STMF_PS_ERROR;
    nvlist_t *groups = NULL, *nvl = NULL;

    if ((groupName == NULL) || (pgName == NULL) || (memberName == NULL)) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    if (iPsConfig == NULL) {
        syslog(LOG_ERR, "can't add group member - extended configuration"
                        " is not loaded");
        return STMF_PS_ERROR;
    }
    /* find groups list */
    if (0 != nvlist_lookup_nvlist(iPsConfig, pgName, &groups)) {
        syslog(LOG_ERR, "can't add group member - group list %s doesn't exist",
               pgName);
        return STMF_PS_ERROR_NOT_FOUND;
    }
    /* find the specified group in the list */
    if (0 != nvlist_lookup_nvlist(groups, groupName, &nvl)) {
        syslog(LOG_ERR, "can't add group member - group %s doesn't exist",
               groupName);
        return STMF_PS_ERROR_GROUP_NOT_FOUND;
    }
    /* check if this member already exists */
    if (B_TRUE == nvlist_exists(nvl, memberName)) {
        syslog(LOG_ERR, "can't add group member - member %s already exists",
               memberName);
        return STMF_PS_ERROR_EXISTS;
    }
    /* add member to the group list */
    if (0 == nvlist_add_string(nvl, memberName, "")) {
        /* save config */
        ret = iPsSaveConfigExt();
    }
    return ret;
}

static int iPsAddViewEntryExt(stmfGuid *luGuid, stmfViewEntry *viewEntry)
{
    nvlist_t *luVes = NULL, *lu = NULL, *ve = NULL;
    int ret = STMF_PS_SUCCESS;
    char buf[8] = "";

    if ((luGuid == NULL) || (viewEntry == NULL)) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    ret = iPsFindLuExt(luGuid, &lu);
    if (ret != STMF_STATUS_SUCCESS) {
        return ret;
    }
    /* check "velist" in lu information */
    if (0 != nvlist_lookup_nvlist(lu, LU_PROP_NAME_VELIST, &luVes)) {
        syslog(LOG_ERR, "can't add VE - VE list doesn't exist");
        return STMF_PS_ERROR_NOT_FOUND;
    }
    /* find this view entry in the list */
    sprintf(buf, "%04X", viewEntry->veIndex);
    if (B_TRUE == nvlist_exists(luVes, buf)) {
        syslog(LOG_ERR, "can't add VE - VE %s already exists", buf);
        return STMF_PS_ERROR_EXISTS;
    }
    /* allocate memory for view entry */
    if (0 != nvlist_alloc(&ve, NV_UNIQUE_NAME, 0)) {
        syslog(LOG_ERR, "can't add VE - not enough memory");
        return STMF_PS_ERROR_NOMEM;
    }
    /* convert VE properties from smfViewEntry to nvlist */
    if (STMF_STATUS_SUCCESS != convertViewEntryToNvl(viewEntry, ve)) {
        syslog(LOG_ERR, "can't add VE - error conerting stmfViewEntry to nvlist");
        nvlist_free(ve);
        return STMF_PS_ERROR;
    }
    /* add VE properties list to the list */
    if (0 == nvlist_add_nvlist(luVes, buf, ve)) {
        /* save config */
        ret = iPsSaveConfigExt();
    }
    if (ret != STMF_STATUS_SUCCESS) {
        nvlist_free(ve);
    }
    return ret;
}

static int iPsClearGroupsExt(char *pgName)
{
    int ret = STMF_PS_ERROR;
    nvlist_t *groups = NULL;

    if (pgName == NULL) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    if (iPsConfig == NULL) {
        syslog(LOG_ERR, "can't clear group list - extended configuration"
                        " is not loaded");
        return STMF_PS_ERROR;
    }
    if (0 != nvlist_lookup_nvlist(iPsConfig, pgName, &groups)) {
        syslog(LOG_ERR, "can't clear group list %s - it doesn't exist", pgName);
        return STMF_PS_ERROR_NOT_FOUND;
    }
    if (0 == iPsClearListMembersExt(groups)) {
        ret = iPsSaveConfigExt();
    }
    return ret;
}

static int iPsCreateGroupExt(char *pgName, char *groupName)
{
    int ret = STMF_PS_ERROR_NOT_FOUND;
    nvlist_t *groups = NULL, *nvl = NULL;

    if ((groupName == NULL) || (pgName == NULL)) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    if (iPsConfig == NULL) {
        syslog(LOG_ERR, "can't create group - extended configuration"
                        " is not loaded");
        return STMF_PS_ERROR;
    }
    if (0 != nvlist_lookup_nvlist(iPsConfig, pgName, &groups)) {
        syslog(LOG_ERR, "can't create group - extended configuration"
                        " doesn't contain %s list", pgName);
        return STMF_PS_ERROR_NOT_FOUND;
    }
    if (0 == nvlist_lookup_nvlist(groups, groupName, &nvl)) {
        syslog(LOG_ERR, "can't create group %s - it already exists", groupName);
        return STMF_PS_ERROR_EXISTS;
    }
    if (0 == nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) {
        if (0 == nvlist_add_nvlist(groups, groupName, nvl)) {
            ret = iPsSaveConfigExt();
        }
        else {
            syslog(LOG_ERR, "can't create group %s", groupName);
            ret = STMF_PS_ERROR;
        }
    }
    else {
        syslog(LOG_ERR, "can't create group %s - not enough memory", groupName);
        ret = STMF_PS_ERROR_NOMEM;
    }
    return ret;
}

static int iPsDeleteGroupExt(char *pgName, char *groupName)
{
    int ret = STMF_PS_ERROR;
    nvlist_t *groups = NULL, *nvl = NULL;

    if ((groupName == NULL) || (pgName == NULL)) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    if (iPsConfig == NULL) {
        syslog(LOG_ERR, "can't delete group - extended configuration"
                        " is not loaded");
        return STMF_PS_ERROR;
    }
    if (0 != nvlist_lookup_nvlist(iPsConfig, pgName, &groups)) {
        syslog(LOG_ERR, "can't delete group - extended configuration"
                        " doesn't contain %s list", pgName);
        return STMF_PS_ERROR_NOT_FOUND;
    }
    if (0 != nvlist_lookup_nvlist(groups, groupName, &nvl)) {
        ret = STMF_PS_SUCCESS;
    }
    else {
        /* remove all group members */
        if (0 != iPsClearListMembersExt(nvl)) {
            /* TODO : one or more members are not removed. What to do? */
            syslog(LOG_ERR, "group was not completely deleted");
        }
        /* remove the group itself */
        if (0 == nvlist_remove(groups, groupName, DATA_TYPE_NVLIST)) {
            ret = iPsSaveConfigExt();
        }
    }
    return ret;
}

static int iPsFromNvlToStmfLuListExt(nvlist_t nvl, stmfGuidList *guidList,
                                     uint64_t guidCnt)
{
    int i = 0;
    nvpair_t *nvp = NULL;

    if (guidList == NULL) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    guidList->cnt = 0;
    nvp = nvlist_next_nvpair(&nvl, NULL);
    while ((nvp != NULL) && (i < guidCnt)) {
        iPsStringToGuid(nvpair_name(nvp), &(guidList->guid[i++]));
        guidList->cnt++;
        nvp = nvlist_next_nvpair(&nvl, nvp);
    }
    return STMF_PS_SUCCESS;
}

static int iPsFromNvlToStmfVeListExt(nvlist_t nvl,
                                     stmfViewEntryList *viewEntryList,
                                     uint64_t veCnt)
{
    int i = 0;
    nvpair_t *nvp = NULL;
    nvlist_t *ve = NULL;

    if (viewEntryList == NULL) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    viewEntryList->cnt = 0;
    nvp = nvlist_next_nvpair(&nvl, NULL);
    while ((nvp != NULL) && (i < veCnt)) {
        nvp = nvlist_next_nvpair(&nvl, nvp);
        if (0 == nvpair_value_nvlist(nvp, &ve)) {
            convertViewEntryFromNvl(ve, &(viewEntryList->ve[i++]));
            viewEntryList->cnt++;
        }
    }

    return STMF_PS_SUCCESS;
}

static int iPsGetActualGroupNameExt(char *pgName, char *groupName,
                                    char *groupPropName)
{
    strcpy(groupPropName, groupName);
    return STMF_PS_SUCCESS;
}

static int iPsGetGroupListExt(char *pgName, stmfGroupList **groupList)
{
    int memberCnt = 0;
    nvlist_t *groups = NULL;
    nvpair_t *nvp = NULL;

    if ((pgName == NULL) || (groupList == NULL)) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    if (iPsConfig == NULL) {
        syslog(LOG_ERR, "can't get group list - extended configuration"
                        " is not loaded");
        return STMF_PS_ERROR;
    }
    if (0 != nvlist_lookup_nvlist(iPsConfig, pgName, &groups)) {
        syslog(LOG_ERR, "can't get group list - extended configuration"
                        " doesn't contain %s list", pgName);
        return STMF_PS_ERROR_NOT_FOUND;
    }
    memberCnt = iPsCountPairs(groups);
    *groupList = (stmfGroupList *)calloc(1, sizeof(stmfGroupList)
                                         + memberCnt*sizeof(stmfGroupName));
    if (*groupList == NULL) {
        syslog(LOG_ERR, "can't get group list - not enough memory");
        return STMF_PS_ERROR_NOMEM;
    }
    nvp = nvlist_next_nvpair(groups, NULL);
    memberCnt = 0;
    while (nvp != NULL) {
        strcpy((*groupList)->name[memberCnt++], nvpair_name(nvp));
        (*groupList)->cnt++;
        nvp = nvlist_next_nvpair(groups, nvp);
    }
    return STMF_PS_SUCCESS;
}

static int iPsGetGroupMemberListExt(char *pgName, char *groupName,
                                    stmfGroupProperties **groupMemberList)
{
    int memberCnt = 0;
    nvlist_t *groups = NULL, *members = NULL;
    nvpair_t *nvp = NULL;
    char *tmp = NULL;

    if ((pgName == NULL) || (groupName == NULL)
        || (groupMemberList == NULL)) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    if (iPsConfig == NULL) {
        syslog(LOG_ERR, "can't get group member list - extended configuration"
                        " is not loaded");
        return STMF_PS_ERROR;
    }
    /* find groups list */
    if (0 != nvlist_lookup_nvlist(iPsConfig, pgName, &groups)) {
        syslog(LOG_ERR, "can't get group member list - extended configuration"
                        " doesn't contain %s list", pgName);
        return STMF_PS_ERROR_NOT_FOUND;
    }
    /* find group */
    if (0 != nvlist_lookup_nvlist(groups, groupName, &members)) {
        syslog(LOG_ERR, "can't get group member list - extended configuration"
                        " doesn't contain %s group data", groupName);
        return STMF_PS_ERROR_NOT_FOUND;
    }
    /* calculate number of members in group list */
    memberCnt = iPsCountPairs(members);
    /* allocate memory */
    *groupMemberList = (stmfGroupProperties *)calloc(1,
                     sizeof(stmfGroupProperties) + memberCnt*sizeof(stmfDevid));
    if (*groupMemberList == NULL) {
        syslog(LOG_ERR, "can't get group member list - not enough memory");
        return STMF_PS_ERROR_NOMEM;
    }
    /* copy data from nvlist_t to stmfGroupList */
    memberCnt = 0;
    nvp = nvlist_next_nvpair(members, NULL);
    while (nvp != NULL) {
        nvp = nvlist_next_nvpair(members, nvp);
        tmp = nvpair_name(nvp);
        (*groupMemberList)->name[memberCnt].identLength = strlen(tmp);
        strcpy((char *)((*groupMemberList)->name[memberCnt++].ident), tmp);
        (*groupMemberList)->cnt++;
        memberCnt++;
    }
    return STMF_PS_SUCCESS;
}

static int iPsGetLogicalUnitListExt(nvlist_t **nvl, int *guidCnt)
{
    if (nvl == NULL) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    if (iPsConfig == NULL) {
        syslog(LOG_ERR, "can't get logical unit list - extended configuration"
                        " is not loaded");
        return STMF_PS_ERROR;
    }
    /* find groups list */
    if (0 != nvlist_lookup_nvlist(iPsConfig, "LU", nvl)) {
        syslog(LOG_ERR, "can't get logical unit list - extended configuration"
                        " doesn't have logical unit section");
        return STMF_PS_ERROR_NOT_FOUND;
    }
    if (guidCnt != NULL) {
        *guidCnt = iPsCountPairs(*nvl);
    }
    return STMF_PS_SUCCESS;
}

static int iPsGetProviderDataExt(char *providerName, nvlist_t **nvl,
                                 int providerType, uint64_t *setToken)
{
    nvlist_t *lulist = NULL, *props = NULL;
    nvpair_t *nvp = NULL;
    char *luguid = NULL, *filenm = NULL;
    int ret = 0, cnt = 0;

    if ((providerName == NULL) || (nvl == NULL)) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    if (iPsConfig == NULL) {
        syslog(LOG_ERR, "can't get provider data - extended configuration"
                        " is not loaded");
        return STMF_PS_ERROR;
    }
    if (providerType == STMF_LU_PROVIDER_TYPE) {
        if (0 != nvlist_lookup_nvlist(iPsConfig, "LU", &lulist)) {
            syslog(LOG_ERR, "can't get provider data - extended configuration"
                            " doesn't have logical unit section");
            return STMF_PS_ERROR_GROUP_NOT_FOUND;
        }
        if (0 != nvlist_alloc(nvl, NV_UNIQUE_NAME, 0)) {
            syslog(LOG_ERR, "can't get provider data - not enough memory");
            return STMF_PS_ERROR_NOMEM;
        }
        ret = 0;
        nvp = nvlist_next_nvpair(lulist, NULL);
        while (nvp != NULL) {
            luguid = nvpair_name(nvp);
            nvpair_value_string(nvp, &filenm);
            if (0 ==  nvlist_add_string(*nvl, luguid, filenm)) {
                cnt++;
            }
            else {
                ret++;
            }
            nvp = nvlist_next_nvpair(lulist, nvp);
        }
        if (setToken != NULL) {
            *setToken = cnt;
        }
        return (ret == 0) ? STMF_PS_SUCCESS : STMF_PS_ERROR;
    }
    /* provider type == STMF_PORT_PROVIDER_TYPE */
    if (0 != nvlist_lookup_nvlist(iPsConfig, "PP", &props)) {
        syslog(LOG_ERR, "can't get provider data - extended configuration"
                        " doesn't have provider data section");
        return STMF_PS_ERROR_GROUP_NOT_FOUND;
    }
    if (0 != nvlist_lookup_nvlist(props, providerName, nvl)) {
        syslog(LOG_ERR, "can't get provider data - data for %s provider"
                        " doesn't exist", providerName);
        return STMF_PS_ERROR;
    }
    if (setToken != NULL) {
        *setToken = iPsCountPairs(*nvl);
    }
    return STMF_PS_SUCCESS;
}

static int iPsGetProviderDataListExt(stmfProviderList **providerList)
{
    nvlist_t *props = NULL;
    nvpair_t *nvp = NULL;
    int providerCnt = 0;

    if (providerList == NULL) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    if (iPsConfig == NULL) {
        syslog(LOG_ERR, "can't get provider data list - extended configuration"
                        " is not loaded");
        return STMF_PS_ERROR;
    }

    /* provider type == STMF_PORT_PROVIDER_TYPE */
    if (0 != nvlist_lookup_nvlist(iPsConfig, "PP", &props)) {
        syslog(LOG_ERR, "can't get provider data list - extended configuration"
                        " doesn't have provider data section");
        return STMF_PS_ERROR_GROUP_NOT_FOUND;
    }
    providerCnt = iPsCountPairs(props);
    *providerList = (stmfProviderList *)calloc(1, sizeof(stmfProviderList)
                                 + (providerCnt + 1)*sizeof(stmfProvider));
    if (*providerList == NULL) {
        syslog(LOG_ERR, "can't get provider data list - not enough memory");
        return STMF_PS_ERROR_NOMEM;
    }
    nvp = nvlist_next_nvpair(props, NULL);
    providerCnt = 0;
    while (nvp != NULL) {
        strcpy((*providerList)->provider[providerCnt].name, nvpair_name(nvp));
        (*providerList)->provider[providerCnt++].providerType =
                                                        STMF_PORT_PROVIDER_TYPE;
        (*providerList)->cnt++;
        nvp = nvlist_next_nvpair(props, nvp);
    }
    strcpy((*providerList)->provider[providerCnt].name, "sbd");
    (*providerList)->provider[providerCnt++].providerType=STMF_LU_PROVIDER_TYPE;
    (*providerList)->cnt++;
    return STMF_PS_SUCCESS;
}

static int iPsGetViewEntryExt(stmfGuid *guid, uint32_t viewEntryIndex,
                              stmfViewEntry *ve)
{
    nvlist_t *luVes = NULL, *lu = NULL;
    int ret = STMF_PS_SUCCESS;
    char buf[8] = "";

    if ((guid == NULL) || (ve == NULL)) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    ret = iPsFindLuExt(guid, &lu);
    if (ret != STMF_STATUS_SUCCESS) {
        return ret;
    }
    /* check "velist" in lu information */
    if (0 != nvlist_lookup_nvlist(lu, LU_PROP_NAME_VELIST, &luVes)) {
        syslog(LOG_ERR, "can't get VE - VE list doesn't exist");
        return STMF_PS_ERROR_NOT_FOUND;
    }
    /* find this view entry in the list */
    sprintf(buf, "%04X", viewEntryIndex);
    if (0 != nvlist_lookup_nvlist(luVes, buf, &lu)) {
        syslog(LOG_ERR, "can't get VE - VE %s doesn't exist", buf);
        return STMF_PS_ERROR_NOT_FOUND;
    }
    return convertViewEntryFromNvl(lu, ve);
}

static int iPsGetViewEntryListExt(stmfGuid *guid, nvlist_t **nvl,
                                  uint64_t *veCnt)
{
    nvlist_t *luVes = NULL, *lu = NULL;
    int ret = STMF_PS_SUCCESS;

    if ((guid == NULL) || (nvl == NULL)) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    ret = iPsFindLuExt(guid, &lu);
    if (ret != STMF_STATUS_SUCCESS) {
        return ret;
    }
    /* check "velist" in lu information */
    if (0 != nvlist_lookup_nvlist(lu, LU_PROP_NAME_VELIST, &luVes)) {
        syslog(LOG_ERR, "can't get VE list - VE list doesn't exist");
        return STMF_PS_ERROR_NOT_FOUND;
    }
    *nvl = luVes;
    if (veCnt != NULL) {
        *veCnt = iPsCountPairs(luVes);
    }
    return ret;
}

static int iPsRemoveGroupMemberExt(char *pgName, char *groupName,
                                   char *memberName)
{
    int ret = STMF_PS_ERROR;
    nvlist_t *groups = NULL, *nvl = NULL;

    if ((groupName == NULL) || (pgName == NULL) || (memberName == NULL)) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    if (iPsConfig == NULL) {
        syslog(LOG_ERR, "can't remove group member - extended configuration"
                        " is not loaded");
        return STMF_PS_ERROR;
    }
    /* find groups list */
    if (0 != nvlist_lookup_nvlist(iPsConfig, pgName, &groups)) {
        syslog(LOG_ERR, "can't remove group member - extended configuration"
                        " doesn't contain %s list", pgName);
        return STMF_PS_ERROR_NOT_FOUND;
    }
    /* find the specified group in the list */
    if (0 != nvlist_lookup_nvlist(groups, groupName, &nvl)) {
        syslog(LOG_ERR, "can't remove group member - extended configuration"
                        " doesn't contain %s group data", groupName);
        return STMF_PS_ERROR_GROUP_NOT_FOUND;
    }
    /* check if this member already exists */
    if (B_FALSE == nvlist_exists(nvl, memberName)) {
        syslog(LOG_ERR, "can't remove group member - group %s doesn't exist",
               memberName);
        return STMF_PS_SUCCESS;
    }
    /* remove member from the group list */
    if (0 == nvlist_remove(nvl, memberName, DATA_TYPE_STRING)) {
        /* save config */
        ret = iPsSaveConfigExt();
    }
    return ret;
}

static int iPsRemoveViewEntryExt(stmfGuid *guid, uint32_t viewEntryIndex)
{
    nvlist_t *luVes = NULL, *lu = NULL, *ve = NULL;
    int ret = STMF_PS_SUCCESS;
    char buf[8] = "";

    if (guid == NULL) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    ret = iPsFindLuExt(guid, &lu);
    if (ret != STMF_STATUS_SUCCESS) {
        return ret;
    }
    /* check "velist" in lu information */
    if (0 != nvlist_lookup_nvlist(lu, LU_PROP_NAME_VELIST, &luVes)) {
        syslog(LOG_ERR, "can't remove VE - VE list doesn't exist");
        return STMF_PS_ERROR_NOT_FOUND;
    }
    /* find this view entry in the list */
    sprintf(buf, "%04X", viewEntryIndex);
    if (0 != nvlist_lookup_nvlist(luVes, buf, &ve)) {
        syslog(LOG_ERR, "can't remove VE - VE %s doesn't exist", buf);
        return STMF_STATUS_SUCCESS;
    }
    /* remove VE from the list */
    if (0 == nvlist_remove(luVes, buf, DATA_TYPE_NVLIST)) {
        nvlist_free(ve);
        /* save config */
        ret = iPsSaveConfigExt();
    }
    else {
        syslog(LOG_ERR, "can't remove VE - nvlist removing error");
        ret = STMF_PS_ERROR;
    }
    return ret;
}

static int iPsSetProviderDataExt(char *providerName, nvlist_t *nvl,
                                 int providerType, uint64_t *setToken)
{
    nvlist_t *lulist = NULL, *ludata = NULL, *props = NULL, *luves = NULL;
    nvpair_t *nvp = NULL;
    char *luguid = NULL, *filenm = NULL;
    int ret = STMF_PS_SUCCESS;

    if ((providerName == NULL) || (nvl == NULL)) {
        return STMF_PS_ERROR_INVALID_ARG;
    }
    if (iPsConfig == NULL) {
        syslog(LOG_ERR, "can't set provider data - extended configuration"
                        " is not loaded");
        return STMF_PS_ERROR;
    }

    if (providerType == STMF_LU_PROVIDER_TYPE) {
        if (0 != nvlist_lookup_nvlist(iPsConfig, "LU", &lulist)) {
            syslog(LOG_ERR, "can't set provider data - extended configuration"
                            " doesn't have logical unit section");
            return STMF_PS_ERROR_GROUP_NOT_FOUND;
        }
        /* Remove all LUs from lulist that do not exist in nvl */
        nvp = nvlist_next_nvpair(lulist, NULL);
        while (nvp != NULL) {
            luguid = nvpair_name(nvp);
            nvpair_value_string(nvp, &filenm);
            /* Remove LU from lulist if it doesn't exist in nvl */
            if (B_FALSE == nvlist_exists(nvl, luguid)) {
                if (0 == nvlist_lookup_nvlist(lulist, luguid, &ludata)) {
                    if (0 != nvlist_remove(lulist, luguid, DATA_TYPE_NVLIST)) {
                        iPsClearListMembersExt(ludata);
                        nvlist_free(ludata);
                    }
                }
            }
            nvp = nvlist_next_nvpair(lulist, nvp);
        }
        /* Add all LUs from nvl that do not exist in lulist */
        nvp = nvlist_next_nvpair(nvl, NULL);
        while (nvp != NULL) {
            luguid = nvpair_name(nvp);
            nvpair_value_string(nvp, &filenm);
            /* Add LU to lulist if it doesn't exist in nvl */
            if (B_FALSE == nvlist_exists(lulist, luguid)) {
                if (0 != nvlist_alloc(&ludata, NV_UNIQUE_NAME, 0)) {
                    syslog(LOG_ERR, "can't set provider data - not enough"
                                    " memory");
                    return STMF_PS_ERROR_NOMEM;
                }
                if (0 != nvlist_alloc(&props, NV_UNIQUE_NAME, 0)) {
                    syslog(LOG_ERR, "can't set provider data - not enough"
                                    " memory");
                    nvlist_free(ludata);
                    return STMF_PS_ERROR_NOMEM;
                }
                if (0 != nvlist_alloc(&luves, NV_UNIQUE_NAME, 0)) {
                    syslog(LOG_ERR, "can't set provider data - not enough"
                                    " memory");
                    nvlist_free(props);
                    nvlist_free(ludata);
                    return STMF_PS_ERROR_NOMEM;
                }
                ret = 0;
                ret += nvlist_add_string(ludata, LU_PROP_NAME_FILE, filenm);
                ret += nvlist_add_string(ludata, LU_PROP_NAME_PROVIDER, providerName);
                ret += nvlist_add_nvlist(ludata, LU_PROP_NAME_PROPERTIES, props);
                ret += nvlist_add_uint32(ludata, LU_PROP_NAME_VECOUNT, 0);
                ret += nvlist_add_nvlist(ludata, LU_PROP_NAME_VELIST, luves);
                ret += nvlist_add_nvlist(lulist, luguid, ludata);
            }
            nvp = nvlist_next_nvpair(nvl, nvp);
        }
        if (ret == 0) {
            ret = iPsSaveConfigExt();
        }
        else {
            syslog(LOG_ERR, "can't set provider data - %i properties were not added",
                   ret );
            ret = STMF_PS_ERROR;
        }
        if (ret != STMF_PS_SUCCESS) {
            nvlist_free(luves);
            nvlist_free(props);
            nvlist_free(ludata);
        }
        return ret;
    }
    /* provider type == STMF_PORT_PROVIDER_TYPE */
    if (0 != nvlist_lookup_nvlist(iPsConfig, "PP", &props)) {
        syslog(LOG_ERR, "can't set provider data list - extended configuration"
                        " doesn't have provider data section");
        ret = STMF_PS_ERROR_GROUP_NOT_FOUND;
    }
    if (B_TRUE == nvlist_exists(props, providerName)) {
        /* remove provider config from the providers list */
        if (0 != nvlist_remove(props, providerName, DATA_TYPE_NVLIST)) {
            syslog(LOG_ERR, "can't set provider data - error removing old data");
            return STMF_PS_ERROR;
        }
    }
    if (0 == nvlist_add_nvlist(props, providerName, nvl)) {
        ret = iPsSaveConfigExt();
    }
    else {
        syslog(LOG_ERR, "can't set provider data - error adding provider data");
        ret = STMF_PS_ERROR;
    }
    return ret;
}

static void iPsFreeConfigExt(void)
{
    nvlist_t *nvl=NULL;

    if (iPsConfig != NULL) {
        if (0 == nvlist_lookup_nvlist(iPsConfig, STMF_HOST_GROUPS, &nvl)) {
            /* free all host groups members */
            iPsClearListMembersExt(nvl);
            nvlist_free(nvl);
            nvl = NULL;
        }
        if (0 == nvlist_lookup_nvlist(iPsConfig, STMF_TARGET_GROUPS, &nvl)) {
            /* free all target groups members */
            iPsClearListMembersExt(nvl);
            nvlist_free(nvl);
            nvl = NULL;
        }
        if (0 == nvlist_lookup_nvlist(iPsConfig, "LU", &nvl)) {
            /* free all logical units */
            iPsClearListMembersExt(nvl);
            nvlist_free(nvl);
            nvl = NULL;
        }
        if (0 == nvlist_lookup_nvlist(iPsConfig, "PP", &nvl)) {
            /* free all provider properties */
            iPsClearListMembersExt(nvl);
            nvlist_free(nvl);
            nvl = NULL;
        }
        nvlist_free(iPsConfig);
        iPsConfig = NULL;
    }
}

static int iPsSaveConfigExt(void)
{
    FILE *fd = NULL;
    size_t bufsz = 0;
    char *buf = NULL;

    if ((strlen(iPsExternalStorage) == 0) || (iPsConfig == NULL)) {
        return STMF_PS_SUCCESS;
    }

    if (0 != nvlist_size(iPsConfig, &bufsz, NV_ENCODE_XDR)) {
        syslog(LOG_ERR, "can't save extended configuration - error list size"
                        " calculation");
        return STMF_PS_ERROR;
    }
    if (0 != nvlist_pack(iPsConfig, &buf, &bufsz, NV_ENCODE_XDR, 0)) {
        syslog(LOG_ERR, "can't save extended configuration - error list"
                        " packing");
        return STMF_PS_ERROR_NOMEM;
    }
    fd = fopen(iPsExternalStorage, "w");
    if (fd == NULL) {
        syslog(LOG_ERR, "can't save extended configuration - error opening %s",
               iPsExternalStorage);
        free(buf);
        return STMF_PS_ERROR;
    }
    /* pack into contig. memory */
    fwrite(buf, bufsz, 1, fd);
    free(buf);
    fclose(fd);
    return STMF_PS_SUCCESS;
}

static int iPsLoadConfigExt(void)
{
    FILE *fd = NULL;
    size_t bufsz = 0;
    char *buf = NULL;
    nvlist_t *hostGroups = NULL, *targetGroups = NULL, *logicalUnits = NULL,
             *providerProps = NULL;
    int res = 0;

    iPsFreeConfigExt();
    if (strlen(iPsExternalStorage) == 0) {
        return STMF_PS_SUCCESS;
    }
    fd = fopen(iPsExternalStorage, "r");
    if (fd == NULL) {
        fd = fopen(iPsExternalStorage, "w+");
        if (fd == NULL) {
            syslog(LOG_ERR, "can't load extended configuration - error opening"
                            " %s", iPsExternalStorage);
            return STMF_PS_ERROR;
        }
        res += nvlist_alloc(&iPsConfig, NV_UNIQUE_NAME, 0);
        res += nvlist_alloc(&hostGroups, NV_UNIQUE_NAME, 0);
        nvlist_add_nvlist(iPsConfig, STMF_HOST_GROUPS, hostGroups);
        res +=  nvlist_alloc(&targetGroups, NV_UNIQUE_NAME, 0);
        nvlist_add_nvlist(iPsConfig, STMF_TARGET_GROUPS, targetGroups);
        res += nvlist_alloc(&logicalUnits, NV_UNIQUE_NAME, 0);
        nvlist_add_nvlist(iPsConfig, "LU", logicalUnits);
        res +=  nvlist_alloc(&providerProps, NV_UNIQUE_NAME, 0);
        nvlist_add_nvlist(iPsConfig, "PP", providerProps);
        if ((res != 0) || (0 != nvlist_size(iPsConfig, &bufsz,
                                            NV_ENCODE_XDR))) {
            syslog(LOG_ERR, "can't load extended configuration - error list size"
                            " calculation");
            fclose(fd);
            iPsFreeConfigExt();
            return STMF_PS_ERROR_NOMEM;
        }
        /* pack into contig. memory */
        if (0 != nvlist_pack(iPsConfig, &buf, &bufsz, NV_ENCODE_XDR, 0)) {
            syslog(LOG_ERR, "can't load extended configuration - error list"
                            " packing");
            fclose(fd);
            iPsFreeConfigExt();
            return STMF_PS_ERROR_NOMEM;
        }
        fwrite(buf, bufsz, 1, fd);
    }
    else {
        fseek(fd, 0, SEEK_END);
        bufsz = ftell(fd);
        fseek(fd, 0, SEEK_SET);
        buf = calloc(bufsz + 1, 1);
        if (buf == NULL) {
            syslog(LOG_ERR, "can't load extended configuration - not enough"
                            " memory");
            fclose(fd);
            return STMF_PS_ERROR_NOMEM;
        }
        fread(buf, bufsz, 1, fd);
        nvlist_unpack(buf, bufsz, &iPsConfig, 0);
    }
    fclose(fd);
    free(buf);
    return STMF_PS_SUCCESS;
}

/***************** EXTENDED MODE FUNCTIONS ****************************/

/*
 * sigHandler
 *
 * Catch the signal and set the global signalsCaught to the signal received
 *
 * signalsCaught will be used by releaseSignal to raise this signal when
 * we're done processing our critical code.
 *
 */
static void
sigHandler(int sig)
{
	(void) sigaddset(&signalsCaught, sig);
}

/*
 * iPsAddRemoveGroupMember
 *
 * Add or remove a member for a given group
 *
 * pgName - Property group name
 * groupName - group name to which the member is added/removed
 * memberName - member to be added/removed
 * addRemoveFlag - ADD/REMOVE
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
static int
iPsAddRemoveGroupMember(char *pgName, char *groupName, char *memberName,
    int addRemoveFlag)
{
	scf_handle_t *handle = NULL;
	scf_service_t *svc = NULL;
	scf_propertygroup_t *pg = NULL;
	scf_property_t *prop = NULL;
	scf_value_t *valueLookup = NULL;
	scf_value_t **valueSet = NULL;
	scf_iter_t *valueIter = NULL;
	scf_transaction_t *tran = NULL;
	scf_transaction_entry_t *entry = NULL;
	int i = 0;
	int lastAlloc;
	int valueArraySize = 0;
	int ret = STMF_PS_SUCCESS;
	char buf[STMF_IDENT_LENGTH];
	int commitRet;
	boolean_t found = B_FALSE;

	assert(pgName != NULL && groupName != NULL && memberName != NULL);

	/*
	 * Init the service handle
	 */
	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	/*
	 * Allocate scf resources
	 */
	if (((pg = scf_pg_create(handle)) == NULL) ||
	    ((tran = scf_transaction_create(handle)) == NULL) ||
	    ((entry = scf_entry_create(handle)) == NULL) ||
	    ((prop = scf_property_create(handle)) == NULL) ||
	    ((valueIter = scf_iter_create(handle)) == NULL)) {
		syslog(LOG_ERR, "scf alloc resource failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * Get the service property group handle
	 */
	if (scf_service_get_pg(svc, pgName, pg) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND) {
			ret = STMF_PS_ERROR_NOT_FOUND;
		} else {
			ret = STMF_PS_ERROR;
		}
		syslog(LOG_ERR, "get pg %s failed - %s",
		    pgName, scf_strerror(scf_error()));

		goto out;
	}

	/*
	 * Begin the transaction
	 */
	if (scf_transaction_start(tran, pg) == -1) {
		syslog(LOG_ERR, "start transaction for %s failed - %s",
		    pgName, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * We're changing an existing property by adding a propval
	 * There are no add semantics in libscf for a property value. We'll
	 * need to read in the current properties and apply them all to the
	 * set and then add the one we were asked to add or omit the one
	 * we were asked to remove.
	 */
	if (scf_transaction_property_change(tran, entry, groupName,
	    SCF_TYPE_USTRING) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND) {
			ret = STMF_PS_ERROR_GROUP_NOT_FOUND;
		} else {
			ret = STMF_PS_ERROR;
			syslog(LOG_ERR, "tran property change %s/%s "
			    "failed - %s", pgName, groupName,
			    scf_strerror(scf_error()));
		}
		goto out;
	}

	/*
	 * Get the property handle
	 */
	if (scf_pg_get_property(pg, groupName, prop) == -1) {
		syslog(LOG_ERR, "get property %s/%s failed - %s",
		    pgName, groupName, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * Value lookup is used to lookup the existing values
	 */
	valueLookup = scf_value_create(handle);
	if (valueLookup == NULL) {
		syslog(LOG_ERR, "scf value alloc for %s failed - %s",
		    pgName, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * valueIter is the iterator handle, create the resource
	 */
	if (scf_iter_property_values(valueIter, prop) == -1) {
		syslog(LOG_ERR, "iter values for %s/%s failed - %s",
		    pgName, groupName, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * Allocate value resource pointers.
	 * We need a value resource for each value as value pointers passed
	 * to libscf cannot be destroyed until the commit or destroy on the
	 * transaction is done.
	 *
	 * We're using GROUP_MEMBER_ALLOC initially. If it's not large
	 * enough, we'll realloc on the fly
	 */
	valueSet = (scf_value_t **)calloc(1, sizeof (*valueSet)
	    * (lastAlloc = GROUP_MEMBER_ALLOC));
	if (valueSet == NULL) {
		ret = STMF_PS_ERROR_NOMEM;
		goto out;
	}

	/*
	 * Iterate through the existing values
	 */
	while (scf_iter_next_value(valueIter, valueLookup) == 1) {
		bzero(buf, sizeof (buf));
		if (scf_value_get_ustring(valueLookup, buf, MAXNAMELEN) == -1) {
			syslog(LOG_ERR, "iter %s/%s value failed - %s",
			    pgName, groupName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}

		/*
		 * Check for existing
		 * If we're adding, it's an error
		 * If we're removing, we skip it and simply not
		 * add it to the set. Subtraction by omission.
		 */
		if ((strlen(buf) == strlen(memberName)) &&
		    bcmp(buf, memberName, strlen(buf)) == 0) {
			if (addRemoveFlag == ADD) {
				ret = STMF_PS_ERROR_EXISTS;
				break;
			} else {
				found = B_TRUE;
				continue;
			}
		}

		/*
		 * Create the value resource for this iteration
		 */
		valueSet[i] = scf_value_create(handle);
		if (valueSet[i] == NULL) {
			syslog(LOG_ERR, "scf value alloc for %s failed - %s",
			    pgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}

		/*
		 * Set the value
		 */
		if (scf_value_set_ustring(valueSet[i], buf) == -1) {
			syslog(LOG_ERR, "set value for %s/%s failed - %s",
			    pgName, groupName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}

		/*
		 * Now add the value
		 */
		if (scf_entry_add_value(entry, valueSet[i]) == -1) {
			syslog(LOG_ERR, "add value for %s/%s failed - %s",
			    pgName, groupName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}

		i++;

		/*
		 * realloc if we've hit the previous alloc size
		 */
		if (i >= lastAlloc) {
			lastAlloc += GROUP_MEMBER_ALLOC;
			valueSet = realloc(valueSet,
			    sizeof (*valueSet) * lastAlloc);
			if (valueSet == NULL) {
				ret = STMF_PS_ERROR;
				break;
			}
		}
	}

	/*
	 * set valueArraySize to final allocated length
	 * so we can use it to destroy the resources correctly
	 */
	valueArraySize = i;

	if (!found && (addRemoveFlag == REMOVE)) {
		ret = STMF_PS_ERROR_MEMBER_NOT_FOUND;
	}

	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	/*
	 * If we're adding, we have one more step. Add the member to the
	 * propval list
	 */
	if (addRemoveFlag == ADD) {
		/*
		 * Now create the new entry
		 */
		valueSet[i] = scf_value_create(handle);
		if (valueSet[i] == NULL) {
			syslog(LOG_ERR, "scf value alloc for %s/%s failed - %s",
			    pgName, groupName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		} else {
			valueArraySize++;
		}

		/*
		 * Set the new member name
		 */
		if (scf_value_set_ustring(valueSet[i], memberName) == -1) {
			syslog(LOG_ERR, "set value for %s/%s failed - %s",
			    pgName, groupName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/*
		 * Add the new member
		 */
		if (scf_entry_add_value(entry, valueSet[i]) == -1) {
			syslog(LOG_ERR, "add value for %s/%s failed - %s",
			    pgName, groupName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	}

	/*
	 * Yes, we're finally done. We actually added or removed one entry
	 * from the list.
	 * Woohoo!
	 */
	if ((commitRet = scf_transaction_commit(tran)) != 1) {
		syslog(LOG_ERR, "transaction commit for %s failed - %s",
		    pgName, scf_strerror(scf_error()));
		if (commitRet == 0) {
			ret = STMF_PS_ERROR_BUSY;
		} else {
			ret = STMF_PS_ERROR;
		}
		goto out;
	}

out:
	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}
	if (tran != NULL) {
		scf_transaction_destroy(tran);
	}
	if (entry != NULL) {
		scf_entry_destroy(entry);
	}
	if (prop != NULL) {
		scf_property_destroy(prop);
	}
	if (valueLookup != NULL) {
		scf_value_destroy(valueLookup);
	}
	if (valueIter != NULL) {
		scf_iter_destroy(valueIter);
	}

	/*
	 * Free valueSet scf resources
	 */
	if (valueArraySize > 0) {
		for (i = 0; i < valueArraySize; i++) {
			scf_value_destroy(valueSet[i]);
		}
	}
	/*
	 * Now free the pointer array to the resources
	 */
	if (valueSet != NULL) {
		free(valueSet);
	}

	return (ret);
}

/*
 * iPsAddRemoveLuViewEntry
 *
 * Adds or removes a view entry name property for a given logical unit
 * property group. There is one logical unit property group for every logical
 * unit that has one or more associated view entries.
 *
 * luPgName - Property group name of logical unit
 * viewEntryPgName - Property group name of view entry
 * addRemoveFlag - ADD_VE/REMOVE_VE
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
static int
iPsAddRemoveLuViewEntry(char *luPgName, char *viewEntryPgName,
    int addRemoveFlag)
{
	scf_handle_t	*handle = NULL;
	scf_service_t	*svc = NULL;
	scf_propertygroup_t	*pg = NULL;
	scf_property_t	*prop = NULL;
	scf_value_t	*value = NULL;
	scf_transaction_t   *tran = NULL;
	scf_transaction_entry_t *entry = NULL;
	scf_transaction_entry_t *entryVeName = NULL;
	boolean_t createVeCnt = B_FALSE;
	uint64_t veCnt = 0;
	int ret = STMF_PS_SUCCESS;
	int commitRet;

	assert(luPgName != NULL || viewEntryPgName != NULL);
	assert(!(addRemoveFlag != ADD && addRemoveFlag != REMOVE));

	/*
	 * Init the service handle
	 */
	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	/*
	 * Allocate scf resources
	 */
	if (((pg = scf_pg_create(handle)) == NULL) ||
	    ((tran = scf_transaction_create(handle)) == NULL) ||
	    ((entry = scf_entry_create(handle)) == NULL) ||
	    ((prop = scf_property_create(handle)) == NULL) ||
	    ((value = scf_value_create(handle)) == NULL)) {
		syslog(LOG_ERR, "scf alloc resource failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/* get the LU property group */
	if (scf_service_get_pg(svc, luPgName, pg) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND &&
		    addRemoveFlag == ADD) {
			/* if it doesn't exist, create it */
			if (scf_service_add_pg(svc, luPgName,
			    SCF_GROUP_APPLICATION, 0, pg) == -1) {
				syslog(LOG_ERR, "add pg %s failed - %s",
				    luPgName, scf_strerror(scf_error()));
				ret = STMF_PS_ERROR;
			} else {
				/* we need to create the VE_CNT property */
				createVeCnt = B_TRUE;
				ret = STMF_PS_SUCCESS;
			}
		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
			ret = STMF_PS_ERROR_NOT_FOUND;
		} else {
			syslog(LOG_ERR, "get lu pg %s failed - %s",
			    luPgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
		}
		if (ret != STMF_PS_SUCCESS) {
			goto out;
		}
	}


	/*
	 * Begin the transaction
	 */
	if (scf_transaction_start(tran, pg) == -1) {
		syslog(LOG_ERR, "start transaction for %s failed - %s",
		    luPgName, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}


	if (createVeCnt) {
		/*
		 * Create the STMF_VE_CNT property. This will keep the current
		 * total view entries for this logical unit.
		 */
		if (scf_transaction_property_new(tran, entry, STMF_VE_CNT,
		    SCF_TYPE_COUNT) == -1) {
			if (scf_error() == SCF_ERROR_EXISTS) {
				ret = STMF_PS_ERROR_EXISTS;
			} else {
				syslog(LOG_ERR,
				    "transaction property new %s/%s "
				    "failed - %s", luPgName, STMF_VE_CNT,
				    scf_strerror(scf_error()));
				ret = STMF_PS_ERROR;
			}
			goto out;
		}
	} else {
		/*
		 * The STMF_VE_CNT property already exists. Just update
		 * it.
		 */
		if (scf_transaction_property_change(tran, entry,
		    STMF_VE_CNT, SCF_TYPE_COUNT) == -1) {
			syslog(LOG_ERR, "transaction property %s/%s change "
			    "failed - %s", luPgName, STMF_VE_CNT,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/*
		 * Get the STMF_VE_CNT property
		 */
		if (scf_pg_get_property(pg, STMF_VE_CNT, prop) == -1) {
			syslog(LOG_ERR, "get property %s/%s failed - %s",
			    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/*
		 * Get the STMF_VE_CNT value
		 */
		if (scf_property_get_value(prop, value) == -1) {
			syslog(LOG_ERR, "get property %s/%s value failed - %s",
			    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/*
		 * Now get the actual value from the value handle
		 */
		if (scf_value_get_count(value, &veCnt) == -1) {
			syslog(LOG_ERR, "get count value %s/%s failed - %s",
			    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/*
		 * Reset the value resource as it is used below
		 */
		scf_value_reset(value);
	}

	if (addRemoveFlag == ADD) {
		veCnt++;
	} else {
		/* Check if this is the last one being removed */
		if (veCnt == 1) {
			/*
			 * Delete the pg and get out if this is the last
			 * view entry
			 */
			if (scf_pg_delete(pg) == -1) {
				syslog(LOG_ERR, "delete pg %s failed - %s",
				    luPgName, scf_strerror(scf_error()));

				ret = STMF_PS_ERROR;
			}
			goto out;
		} else {
			veCnt--;
		}
	}


	/*
	 * Set the view entry count
	 */
	scf_value_set_count(value, veCnt);

	/*
	 * Add the value to the transaction entry
	 */
	if (scf_entry_add_value(entry, value) == -1) {
		syslog(LOG_ERR, "add value %s/%s failed - %s",
		    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * Create a transaction entry resource for the view entry name
	 */
	entryVeName = scf_entry_create(handle);
	if (entryVeName == NULL) {
		syslog(LOG_ERR, "scf transaction entry alloc %s/%s failed - %s",
		    luPgName, viewEntryPgName, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	if (addRemoveFlag == ADD) {
		/*
		 * If adding, create a property with the view entry name
		 */
		if (scf_transaction_property_new(tran, entryVeName,
		    viewEntryPgName, SCF_TYPE_USTRING) == -1) {
			if (scf_error() == SCF_ERROR_EXISTS) {
				ret = STMF_PS_ERROR_EXISTS;
			} else {
				syslog(LOG_ERR,
				    "transaction property new %s/%s "
				    "failed - %s", luPgName, viewEntryPgName,
				    scf_strerror(scf_error()));
				ret = STMF_PS_ERROR;
			}
			goto out;
		}
	} else {
		/*
		 * If removing, delete the existing property with the view
		 * entry name
		 */
		if (scf_transaction_property_delete(tran, entryVeName,
		    viewEntryPgName) == -1) {
			if (scf_error() == SCF_ERROR_NOT_FOUND) {
				ret = STMF_PS_ERROR_NOT_FOUND;
			} else {
				syslog(LOG_ERR,
				    "transaction property delete %s/%s "
				    "failed - %s", luPgName, viewEntryPgName,
				    scf_strerror(scf_error()));
				ret = STMF_PS_ERROR;
			}
			goto out;
		}
	}

	/*
	 * Commit property transaction
	 */
	if ((commitRet = scf_transaction_commit(tran)) != 1) {
		syslog(LOG_ERR, "transaction commit for %s failed - %s",
		    luPgName, scf_strerror(scf_error()));
		if (commitRet == 0) {
			ret = STMF_PS_ERROR_BUSY;
		} else {
			ret = STMF_PS_ERROR;
		}
		goto out;
	}

out:
	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}
	if (tran != NULL) {
		scf_transaction_destroy(tran);
	}
	if (entry != NULL) {
		scf_entry_destroy(entry);
	}
	if (entryVeName != NULL) {
		scf_entry_destroy(entryVeName);
	}
	if (prop != NULL) {
		scf_property_destroy(prop);
	}
	if (value != NULL) {
		scf_value_destroy(value);
	}

	return (ret);
}

/*
 * iPsAddViewEntry
 *
 * Add a view entry property group and optionally, a logical unit property
 * group if it does not exist.
 *
 * luName - ascii hexadecimal logical unit identifier
 * viewEntryName - name of view entry (VIEW_ENTRY_nn)
 * viewEntry - pointer to stmfViewEntry structure
 */
static int
iPsAddViewEntry(char *luPgName, char *viewEntryPgName, stmfViewEntry *viewEntry)
{
	scf_handle_t	*handle = NULL;
	scf_service_t	*svc = NULL;
	scf_propertygroup_t	*pg = NULL;
	scf_value_t	*value[VIEW_ENTRY_STRUCT_CNT];
	scf_transaction_t   *tran = NULL;
	scf_transaction_entry_t *entry[VIEW_ENTRY_STRUCT_CNT];
	int i = 0;
	int j = 0;
	int ret;
	uint8_t scfBool;
	boolean_t createdVePg = B_FALSE;
	int backoutRet;
	int commitRet;

	assert(luPgName != NULL || viewEntryPgName != NULL ||
	    viewEntry == NULL);

	bzero(value, sizeof (value));
	bzero(entry, sizeof (entry));

	/*
	 * Init the service handle
	 */
	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	/*
	 * Allocate scf resources
	 */
	if (((pg = scf_pg_create(handle)) == NULL) ||
	    ((tran = scf_transaction_create(handle)) == NULL)) {
		syslog(LOG_ERR, "scf alloc resource failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * allocate value and entry resources for scf
	 */
	for (i = 0; i < VIEW_ENTRY_STRUCT_CNT; i++) {
		if (((value[i] = scf_value_create(handle)) == NULL) ||
		    ((entry[i] = scf_entry_create(handle)) == NULL)) {
			syslog(LOG_ERR, "scf alloc resource failed - %s",
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	}

	i = 0;

	/*
	 * Create the View Entry property group
	 */
	if (scf_service_add_pg(svc, viewEntryPgName, SCF_GROUP_APPLICATION,
	    0, pg) == -1) {
		if (scf_error() == SCF_ERROR_EXISTS) {
			ret = STMF_PS_ERROR_EXISTS;
		} else {
			syslog(LOG_ERR, "add pg %s failed - %s",
			    viewEntryPgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
		}
		goto out;
	}

	createdVePg = B_TRUE;

	/*
	 * Add the view entry as properties on the view entry group
	 */

	/*
	 * Begin property update transaction
	 */
	if (scf_transaction_start(tran, pg) == -1) {
		syslog(LOG_ERR, "start transaction for add %s failed - %s",
		    viewEntryPgName, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * Add allHosts property
	 */
	if (scf_transaction_property_new(tran, entry[i],
	    STMF_VE_ALLHOSTS, SCF_TYPE_BOOLEAN) == -1) {
		if (scf_error() == SCF_ERROR_EXISTS) {
			ret = STMF_PS_ERROR_EXISTS;
		} else {
			syslog(LOG_ERR, "transaction property new %s/%s "
			    "failed - %s", viewEntryPgName, STMF_VE_ALLHOSTS,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
		}
		goto out;
	}

	/* Set the allHosts value */
	scfBool = viewEntry->allHosts;
	scf_value_set_boolean(value[i], scfBool);

	/*
	 * Add the allHosts value to the transaction
	 */
	if (scf_entry_add_value(entry[i], value[i]) == -1) {
		syslog(LOG_ERR, "add value %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_ALLHOSTS,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	i++;

	/*
	 * Create hostGroup property
	 */
	if (scf_transaction_property_new(tran, entry[i],
	    STMF_VE_HOSTGROUP, SCF_TYPE_USTRING) == -1) {
		if (scf_error() == SCF_ERROR_EXISTS) {
			ret = STMF_PS_ERROR_EXISTS;
		} else {
			syslog(LOG_ERR, "transaction property new %s/%s "
			    "failed - %s", viewEntryPgName, STMF_VE_HOSTGROUP,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
		}
		goto out;
	}

	/*
	 * Set the value for hostGroup
	 */
	if (scf_value_set_ustring(value[i], viewEntry->hostGroup) == -1) {
		syslog(LOG_ERR, "set value %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_HOSTGROUP,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * Add the hostGroup value to the transaction entry
	 */
	if (scf_entry_add_value(entry[i], value[i]) == -1) {
		syslog(LOG_ERR, "add value %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_HOSTGROUP,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	i++;

	/*
	 * Create the allTargets property
	 */
	if (scf_transaction_property_new(tran, entry[i],
	    STMF_VE_ALLTARGETS, SCF_TYPE_BOOLEAN) == -1) {
		if (scf_error() == SCF_ERROR_EXISTS) {
			ret = STMF_PS_ERROR_EXISTS;
		} else {
			syslog(LOG_ERR, "transaction property new %s/%s "
			    "failed - %s", viewEntryPgName, STMF_VE_ALLTARGETS,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
		}
		goto out;
	}

	/*
	 * Set the allTargets value
	 */
	scfBool = viewEntry->allTargets;
	scf_value_set_boolean(value[i], scfBool);

	/*
	 * Add the allTargets value to the transaction
	 */
	if (scf_entry_add_value(entry[i], value[i]) == -1) {
		syslog(LOG_ERR, "add value %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_ALLTARGETS,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	i++;

	/*
	 * Create targetGroup property
	 */
	if (scf_transaction_property_new(tran, entry[i],
	    STMF_VE_TARGETGROUP, SCF_TYPE_USTRING) == -1) {
		if (scf_error() == SCF_ERROR_EXISTS) {
			ret = STMF_PS_ERROR_EXISTS;
		} else {
			syslog(LOG_ERR, "transaction property new %s/%s "
			    "failed - %s", viewEntryPgName,
			    STMF_VE_TARGETGROUP, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
		}
		goto out;
	}

	/*
	 * Set the value for targetGroup
	 */
	if (scf_value_set_ustring(value[i], viewEntry->targetGroup) == -1) {
		syslog(LOG_ERR, "set value %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_TARGETGROUP,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * Add targetGroup value to the transaction
	 */
	if (scf_entry_add_value(entry[i], value[i]) == -1) {
		syslog(LOG_ERR, "add value %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_TARGETGROUP,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	i++;

	/*
	 * Create the luNbr property
	 */
	if (scf_transaction_property_new(tran, entry[i], STMF_VE_LUNBR,
	    SCF_TYPE_OPAQUE) == -1) {
		if (scf_error() == SCF_ERROR_EXISTS) {
			ret = STMF_PS_ERROR_EXISTS;
		} else {
			syslog(LOG_ERR, "transaction property new %s/%s "
			    "failed - %s", viewEntryPgName, STMF_VE_LUNBR,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
		}
		goto out;
	}

	/*
	 * Set the luNbr
	 */
	if (scf_value_set_opaque(value[i], (char *)viewEntry->luNbr,
	    sizeof (viewEntry->luNbr)) == -1) {
		syslog(LOG_ERR, "set value %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_LUNBR, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * Add luNbr to the transaction entry
	 */
	if (scf_entry_add_value(entry[i], value[i]) == -1) {
		syslog(LOG_ERR, "add value %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_LUNBR, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * Now that we've successfully added the view entry,
	 * update the logical unit property group or create
	 * it if it does not exist
	 */
	ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName, ADD);

	/*
	 * If we did not add the view entry name to the logical unit,
	 * make sure we do not commit the transaction
	 */
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	/*
	 * Commit property transaction
	 */
	if ((commitRet = scf_transaction_commit(tran)) != 1) {
		syslog(LOG_ERR, "transaction commit for add %s failed - %s",
		    viewEntryPgName, scf_strerror(scf_error()));
		if (commitRet == 0) {
			ret = STMF_PS_ERROR_BUSY;
		} else {
			ret = STMF_PS_ERROR;
		}
	}

	if (ret != STMF_PS_SUCCESS) {
		/*
		 * If we did not commit, try to remove the view entry name
		 * from the logical unit.
		 * If that fails, we're now inconsistent.
		 */
		backoutRet = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName,
		    REMOVE);

		if (backoutRet != STMF_PS_SUCCESS) {
			syslog(LOG_ERR, "remove lu view entry %s failed"
			    "possible inconsistency - %s", luPgName,
			    scf_strerror(scf_error()));
		}
		/*
		 * We are still in an error scenario even though the remove
		 * lu view entry succeeded.
		 */
		goto out;
	}

out:
	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	/* if there was an error, delete the created pg if one was created */
	if ((ret != STMF_PS_SUCCESS) && createdVePg) {
		if (scf_pg_delete(pg) == -1) {
			syslog(LOG_ERR, "delete VE pg %s failed - %s",
			    viewEntryPgName, scf_strerror(scf_error()));
		}
	}
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}
	if (tran != NULL) {
		scf_transaction_destroy(tran);
	}
	/*
	 * Free value and entry scf resources
	 */
	if (i > 0) {
		for (j = 0; j < VIEW_ENTRY_STRUCT_CNT; j++) {
			if (value[j] != NULL)
				scf_value_destroy(value[j]);
			if (entry[j] != NULL)
				scf_entry_destroy(entry[j]);
		}
	}

	return (ret);
}
/*
 * psClearProviderData
 *
 * providerName - name of provider data to clear
 */
int
psClearProviderData(char *providerName, int providerType)
{
	scf_handle_t	*handle = NULL;
	scf_service_t	*svc = NULL;
	scf_propertygroup_t	*pg = NULL;
	char pgName[MAXPATHLEN];
	int ret = STMF_PS_SUCCESS;
	boolean_t pgNotFound = B_FALSE;

	if (providerName == NULL || (providerType != STMF_LU_PROVIDER_TYPE &&
	    providerType != STMF_PORT_PROVIDER_TYPE)) {
		ret = STMF_PS_ERROR_INVALID_ARG;
		goto out;
	}

	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	/*
	 * Allocate scf resources
	 */
	if ((pg = scf_pg_create(handle)) == NULL) {
		syslog(LOG_ERR, "scf alloc resource failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * create the property group name
	 */
	(void) snprintf(pgName, sizeof (pgName), "%s%s",
	    STMF_PROVIDER_DATA_PREFIX, providerName);

	/*
	 * delete provider property group
	 */
	if (scf_service_get_pg(svc, pgName, pg) == -1) {
		if (scf_error() != SCF_ERROR_NOT_FOUND) {
			syslog(LOG_ERR, "get pg %s failed - %s",
			    pgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		} else {
			pgNotFound = B_TRUE;
		}
	}

	if (!pgNotFound && (scf_pg_delete(pg) == -1)) {
		syslog(LOG_ERR, "delete pg %s failed - %s",
		    pgName, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	if (pgNotFound) {
		ret = STMF_PS_ERROR_NOT_FOUND;
	}

out:
	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}

	return (ret);
}

/*
 * iPsClearGroups
 *
 * Deletes all groups (target or host)
 *
 * pgName - Property group name
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
static int
iPsClearGroups(char *pgRefName)
{
	scf_handle_t            *handle   = NULL;
	scf_service_t           *svc      = NULL;
	scf_propertygroup_t     *pg       = NULL;
	scf_property_t          *prop     = NULL;
	scf_iter_t              *propIter = NULL;
	scf_transaction_t       *tran     = NULL;
	scf_transaction_entry_t *entry1   = NULL;
	scf_transaction_entry_t *entry2   = NULL;
	char buf1[MAXNAMELEN];
	char buf2[MAXNAMELEN];
	int  ret = STMF_PS_SUCCESS;
	int  commitRet;

	assert(pgRefName != NULL);
	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}
	/*
	 * Allocate scf resources
	 */
	if (((pg = scf_pg_create(handle)) == NULL) ||
        ((tran = scf_transaction_create(handle)) == NULL) ||
	    ((entry1 = scf_entry_create(handle)) == NULL) ||
        ((entry2 = scf_entry_create(handle)) == NULL) ||
	    ((prop = scf_property_create(handle)) == NULL) ||
        ((propIter = scf_iter_create(handle)) == NULL)) {
		syslog(LOG_ERR, "scf alloc resource failed - %s",
               scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}
	/*
	 * Get the property group being modified
	 */
	if (scf_service_get_pg(svc, pgRefName, pg) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND) {
			syslog(LOG_ERR, "get pg %s failed - %s", pgRefName,
                   scf_strerror(scf_error()));
			ret = STMF_PS_ERROR_NOT_FOUND;
		} else {
			syslog(LOG_ERR, "get pg %s failed - %s", pgRefName,
                   scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
		}
		if (ret != STMF_PS_SUCCESS) {
			goto out;
		}
	}
	/*
	 * propIter is the iterator handle
	 */
	if (scf_iter_pg_properties(propIter, pg) == -1) {
		syslog(LOG_ERR, "iter properties for %s failed - %s", pgRefName,
               scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}
	/*
	 * Iterate through the group names.
	 */
	while (scf_iter_next_property(propIter, prop) == 1) {
		if (scf_property_get_name(prop, buf1, sizeof (buf1)) == -1) {
			syslog(LOG_ERR, "get name from %s iter failed - %s", pgRefName,
                   scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}
		/*
		 * Skip over member list properties
		 */
		if (strstr(buf1, STMF_MEMBER_LIST_SUFFIX)) {
			continue;
		}
		/*
		 * buf1 contains the name for REMOVE
		 * Now create the new member list property for the new group
		 */
		if (snprintf(buf2, sizeof (buf2), "%s-%s", buf1,
                     STMF_MEMBER_LIST_SUFFIX) > sizeof (buf2)) {
			syslog(LOG_ERR, "buffer overflow on property name %s", buf1);
			ret = STMF_PS_ERROR;
			break;
		}
		/*
		 * buf1 now contains the name of the property
		 * buf2 now contains the member list property name
		 */
		if (scf_transaction_start(tran, pg) == -1) {
			syslog(LOG_ERR, "start transaction for %s failed - %s", pgRefName,
                   scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}
		/*
		 * Delete the property 'group name'
		 */
		if (scf_transaction_property_delete(tran, entry1, buf1) == -1) {
			syslog(LOG_ERR, "transaction property delete %s/%s failed - %s",
                   pgRefName, buf1, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}
		/*
		 * Delete the property 'group list'
		 */
		if (scf_transaction_property_delete(tran, entry2, buf2) == -1) {
			syslog(LOG_ERR, "transaction property delete %s/%s failed - %s",
                   pgRefName, buf2, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}
	  	if ((commitRet = scf_transaction_commit(tran)) != 1) {
			syslog(LOG_ERR, "transaction commit for %s failed - %s", pgRefName,
                   scf_strerror(scf_error()));
			if (commitRet == 0) {
				ret = STMF_PS_ERROR_BUSY;
			} else {
				ret = STMF_PS_ERROR;
			}
			break;
		}
	}
out:
	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}
	if (tran != NULL) {
		scf_transaction_destroy(tran);
	}
	if (entry1 != NULL) {
		scf_entry_destroy(entry1);
	}
	if (entry2 != NULL) {
		scf_entry_destroy(entry2);
	}
	if (prop != NULL) {
		scf_property_destroy(prop);
	}
	if (propIter != NULL) {
		scf_iter_destroy(propIter);
	}
	return (ret);
}

/*
 * iPsCreateDeleteGroup
 *
 * Creates or deletes a group (target or host)
 *
 * When creating a group, two properties are created. One to hold the group
 * name and the other to hold the group members.
 *
 * pgName - Property group name
 * groupName - group name to create
 * addRemoveFlag - ADD_GROUP/REMOVE_GROUP
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
static int
iPsCreateDeleteGroup(char *pgRefName, char *groupName, int addRemoveFlag)
{
	scf_handle_t	*handle = NULL;
	scf_service_t	*svc = NULL;
	scf_propertygroup_t	*pg = NULL;
	scf_property_t	*prop = NULL;
	scf_iter_t	*propIter = NULL;
	scf_transaction_t   *tran = NULL;
	scf_transaction_entry_t *entry1 = NULL;
	scf_transaction_entry_t *entry2 = NULL;
	scf_value_t *value = NULL;
	uint64_t groupIdx;
	char buf1[MAXNAMELEN];
	char buf2[MAXNAMELEN];
	char tmpbuf[MAXNAMELEN];
	boolean_t found = B_FALSE;
	int ret = STMF_PS_SUCCESS;
	int commitRet;

	assert(groupName != NULL);

	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	/*
	 * Allocate scf resources
	 */
	if (((pg = scf_pg_create(handle)) == NULL) ||
	    ((tran = scf_transaction_create(handle)) == NULL) ||
	    ((entry1 = scf_entry_create(handle)) == NULL) ||
	    ((entry2 = scf_entry_create(handle)) == NULL) ||
	    ((prop = scf_property_create(handle)) == NULL) ||
	    ((propIter = scf_iter_create(handle)) == NULL) ||
	    ((value = scf_value_create(handle)) == NULL)) {
		syslog(LOG_ERR, "scf alloc resource failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * Get the property group being modified
	 */
	if (scf_service_get_pg(svc, pgRefName, pg) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND &&
		    addRemoveFlag == ADD) {
			if (scf_service_add_pg(svc, pgRefName,
			    SCF_GROUP_APPLICATION, 0, pg) == -1) {
				syslog(LOG_ERR, "add pg %s failed - %s",
				    pgRefName, scf_strerror(scf_error()));
				ret = STMF_PS_ERROR;
			}
		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
			syslog(LOG_ERR, "get pg %s failed - %s",
			    pgRefName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR_NOT_FOUND;
		} else {
			syslog(LOG_ERR, "get pg %s failed - %s",
			    pgRefName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
		}
		if (ret != STMF_PS_SUCCESS) {
			goto out;
		}
	}

	/*
	 * propIter is the iterator handle
	 */
	if (scf_iter_pg_properties(propIter, pg) == -1) {
		syslog(LOG_ERR, "iter properties for %s failed - %s",
		    pgRefName, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * Iterate through the group names.
	 * If we find it in the list, it's an error when addRemoveFlag == ADD.
	 */
	while (scf_iter_next_property(propIter, prop) == 1) {
		if (scf_property_get_name(prop, buf1, sizeof (buf1)) == -1) {
			syslog(LOG_ERR, "get name from %s iter failed - %s",
			    pgRefName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}
		/*
		 * Skip over member list properties
		 */
		if (strstr(buf1, STMF_MEMBER_LIST_SUFFIX)) {
			continue;
		}
		if (scf_property_get_value(prop, value) == -1) {
			syslog(LOG_ERR, "get property value %s/%s failed - %s",
			    pgRefName, buf1, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}
		if (scf_value_get_ustring(value, tmpbuf,
		    sizeof (tmpbuf)) == -1) {
			syslog(LOG_ERR, "get ustring %s/%s failed - %s",
			    pgRefName, buf1, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}

		if ((strlen(tmpbuf) == strlen(groupName)) &&
		    bcmp(tmpbuf, groupName, strlen(tmpbuf)) == 0) {
			if (addRemoveFlag == ADD) {
				ret = STMF_PS_ERROR_EXISTS;
			}
			found = B_TRUE;
			/*
			 * buf1 contains the name for REMOVE
			 */
			break;
		}
	}

	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	scf_value_reset(value);

	if (!found && addRemoveFlag == REMOVE) {
		ret = STMF_PS_ERROR_NOT_FOUND;
		goto out;
	}

	/*
	 * If we're adding, we need to create a new property name for the
	 * new group
	 */
	if (addRemoveFlag == ADD) {
		for (groupIdx = 0; groupIdx < GROUP_MAX; groupIdx++) {
			if (snprintf(buf1, sizeof (buf1), "%s-%lld",
			    STMF_GROUP_PREFIX, groupIdx) > sizeof (buf1)) {
				syslog(LOG_ERR,
				    "buffer overflow on property name %s",
				    buf1);
				ret = STMF_PS_ERROR;
				break;
			}
			if (scf_pg_get_property(pg, buf1, prop) == -1) {
				if (scf_error() != SCF_ERROR_NOT_FOUND) {
					syslog(LOG_ERR, "get property %s/%s "
					    "failed - %s", pgRefName, buf1,
					    scf_strerror(scf_error()));
					ret = STMF_PS_ERROR;
				}
				break;
			}
		}
	}

	/*
	 * Now create the new member list property for the new group
	 */
	if (snprintf(buf2, sizeof (buf2), "%s-%s", buf1,
	    STMF_MEMBER_LIST_SUFFIX) > sizeof (buf2)) {
		syslog(LOG_ERR, "buffer overflow on property name %s",
		    buf1);
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * buf1 now contains the name of the property if it was found in the
	 * list in the case of delete or the next available property name
	 * in the case of create
	 *
	 * buf2 now contains the member list property name
	 */
	if (scf_transaction_start(tran, pg) == -1) {
		syslog(LOG_ERR, "start transaction for %s failed - %s",
		    pgRefName, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	if (addRemoveFlag == ADD) {
		/*
		 * Create the property 'group name'
		 * This is the container for the group name
		 */
		if (scf_transaction_property_new(tran, entry1, buf1,
		    SCF_TYPE_USTRING) == -1) {
			syslog(LOG_ERR, "transaction property new %s/%s "
			    "failed - %s", pgRefName, buf1,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
		if (scf_value_set_ustring(value, groupName) == -1) {
			syslog(LOG_ERR, "set ustring %s/%s failed - %s",
			    pgRefName, buf1, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
		if (scf_entry_add_value(entry1, value) == -1) {
			syslog(LOG_ERR, "add value %s/%s failed - %s",
			    pgRefName, buf1, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
		/*
		 * Create the property 'group list'
		 * This is the container for the group members
		 */
		if (scf_transaction_property_new(tran, entry2, buf2,
		    SCF_TYPE_USTRING) == -1) {
			syslog(LOG_ERR, "transaction property new %s/%s "
			    "failed - %s", pgRefName, buf2,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	} else {
		/*
		 * Delete the property 'group name'
		 */
		if (scf_transaction_property_delete(tran, entry1, buf1)
		    == -1) {
			syslog(LOG_ERR,
			    "transaction property delete %s/%s failed - %s",
			    pgRefName, buf1, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
		/*
		 * Delete the property 'group list'
		 */
		if (scf_transaction_property_delete(tran, entry2, buf2)
		    == -1) {
			syslog(LOG_ERR, "transaction property delete %s/%s "
			    "failed - %s", pgRefName, buf2,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	}

	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	if ((commitRet = scf_transaction_commit(tran)) != 1) {
		syslog(LOG_ERR, "transaction commit for %s failed - %s",
		    pgRefName, scf_strerror(scf_error()));
		if (commitRet == 0) {
			ret = STMF_PS_ERROR_BUSY;
		} else {
			ret = STMF_PS_ERROR;
		}
	}

out:
	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}
	if (tran != NULL) {
		scf_transaction_destroy(tran);
	}
	if (entry1 != NULL) {
		scf_entry_destroy(entry1);
	}
	if (entry2 != NULL) {
		scf_entry_destroy(entry2);
	}
	if (prop != NULL) {
		scf_property_destroy(prop);
	}
	if (propIter != NULL) {
		scf_iter_destroy(propIter);
	}
	if (value != NULL) {
		scf_value_destroy(value);
	}

	return (ret);
}

/*
 * iPsGetGroupList
 *
 * pgName - Property group name
 * groupList - pointer to pointer to stmfGroupList structure. On success,
 * contains the list of groups
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
static int
iPsGetGroupList(char *pgName, stmfGroupList **groupList)
{
	scf_handle_t	*handle = NULL;
	scf_service_t	*svc = NULL;
	scf_propertygroup_t	*pg = NULL;
	scf_property_t	*prop = NULL;
	scf_iter_t	*propIter = NULL;
	scf_value_t	*value = NULL;
	char buf[MAXNAMELEN];
	int memberCnt = 0;
	int i = 0;
	int ret = STMF_PS_SUCCESS;

	assert(groupList != NULL);

	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	/*
	 * Allocate scf resources
	 */
	if (((pg = scf_pg_create(handle)) == NULL) ||
	    ((prop = scf_property_create(handle)) == NULL) ||
	    ((propIter = scf_iter_create(handle)) == NULL) ||
	    ((value = scf_value_create(handle)) == NULL)) {
		syslog(LOG_ERR, "scf alloc resource failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	if (scf_service_get_pg(svc, pgName, pg) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND) {
			syslog(LOG_ERR, "get pg %s failed - %s",
			    pgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR_NOT_FOUND;
		} else {
			syslog(LOG_ERR, "get pg %s failed - %s",
			    pgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
		}
		goto out;
	}

	/*
	 * propIter is the iterator handle
	 */
	if (scf_iter_pg_properties(propIter, pg) == -1) {
		syslog(LOG_ERR, "iter properties for %s failed - %s",
		    pgName, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	while (scf_iter_next_property(propIter, prop) == 1) {
		if (scf_property_get_name(prop, buf, sizeof (buf)) == -1) {
			syslog(LOG_ERR, "get name from %s iter failed - %s",
			    pgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}
		/*
		 * Skip over member list properties
		 */
		if (strstr(buf, STMF_MEMBER_LIST_SUFFIX)) {
			continue;
		}
		memberCnt++;
	}

	/*
	 * propIter is the iterator handle
	 */
	if (scf_iter_pg_properties(propIter, pg) == -1) {
		syslog(LOG_ERR, "iter properties for %s failed - %s",
		    pgName, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	*groupList = (stmfGroupList *)calloc(1, sizeof (stmfGroupList) +
	    memberCnt * sizeof (stmfGroupName));

	if (*groupList == NULL) {
		ret = STMF_PS_ERROR_NOMEM;
		goto out;
	}

	/*
	 * In order to get a list of groups, simply get all of the
	 * properties that are not member list properties, i.e. the group
	 * name properties.
	 * It's possible for this list to grow beyond what was originally
	 * read so just ensure we're not writing beyond our allocated buffer
	 * by ensuring i < memberCnt
	 */
	while ((scf_iter_next_property(propIter, prop) == 1) &&
	    (i < memberCnt)) {
		if (scf_property_get_name(prop, buf, sizeof (buf)) == -1) {
			syslog(LOG_ERR, "get name from %s iter failed - %s",
			    pgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}
		/*
		 * Skip over member list properties
		 */
		if (strstr(buf, STMF_MEMBER_LIST_SUFFIX)) {
			continue;
		}
		if (scf_property_get_value(prop, value) == -1) {
			syslog(LOG_ERR, "get property value %s/%s failed - %s",
			    pgName, buf, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}
		if (scf_value_get_ustring(value, buf, sizeof (buf)) == -1) {
			syslog(LOG_ERR, "get ustring %s/%s failed - %s",
			    pgName, buf, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}
		bcopy(buf, (*groupList)->name[i++], strlen(buf));
		(*groupList)->cnt++;
	}

	if (ret != STMF_PS_SUCCESS) {
		free(*groupList);
		goto out;
	}

out:
	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}
	if (propIter != NULL) {
		scf_iter_destroy(propIter);
	}
	if (prop != NULL) {
		scf_property_destroy(prop);
	}
	if (value != NULL) {
		scf_value_destroy(value);
	}

	return (ret);
}

/*
 * iPsGetGroupMemberList
 *
 * pgName - Property group name
 * groupName - group name (host group or target group)
 * groupMemberList - pointer to pointer to stmfGroupProperties structure. On
 * success, contains the list of group members
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
static int
iPsGetGroupMemberList(char *pgName, char *groupName,
    stmfGroupProperties **groupMemberList)
{
	scf_handle_t	*handle = NULL;
	scf_service_t	*svc = NULL;
	scf_propertygroup_t	*pg = NULL;
	scf_property_t	*prop = NULL;
	scf_value_t	*valueLookup = NULL;
	scf_iter_t	*valueIter = NULL;
	int i = 0;
	int memberCnt;
	int len;
	int ret = STMF_PS_SUCCESS;
	char buf[MAXNAMELEN];

	assert(pgName != NULL && groupName != NULL);

	/*
	 * init the service handle
	 */
	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	/*
	 * Allocate scf resources
	 */
	if (((pg = scf_pg_create(handle)) == NULL) ||
	    ((prop = scf_property_create(handle)) == NULL) ||
	    ((valueIter = scf_iter_create(handle)) == NULL) ||
	    ((valueLookup = scf_value_create(handle)) == NULL)) {
		syslog(LOG_ERR, "scf alloc resource failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * get the service property group handle
	 */
	if (scf_service_get_pg(svc, pgName, pg) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND) {
			ret = STMF_PS_ERROR_NOT_FOUND;
		} else {
			ret = STMF_PS_ERROR;
		}
		syslog(LOG_ERR, "get pg %s failed - %s",
		    pgName, scf_strerror(scf_error()));
		goto out;
	}

	/*
	 * Get the property handle
	 * based on the target or host group name
	 */
	if (scf_pg_get_property(pg, groupName, prop) == -1) {
		syslog(LOG_ERR, "get property %s/%s failed - %s",
		    pgName, groupName, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * valueIter is the iterator handle
	 */
	if (scf_iter_property_values(valueIter, prop) == -1) {
		syslog(LOG_ERR, "iter value %s/%s failed - %s",
		    pgName, groupName, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	while (scf_iter_next_value(valueIter, valueLookup) == 1) {
		if (scf_value_get_ustring(valueLookup, buf, MAXNAMELEN) == -1) {
			syslog(LOG_ERR, "iter value %s/%s failed - %s",
			    pgName, groupName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}
		i++;
	}

	/*
	 * valueIter is the iterator handle
	 */
	if (scf_iter_property_values(valueIter, prop) == -1) {
		syslog(LOG_ERR, "iter value %s/%s failed - %s",
		    pgName, groupName, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	memberCnt = i;

	*groupMemberList = (stmfGroupProperties *)calloc(1,
	    sizeof (stmfGroupProperties) + memberCnt * sizeof (stmfDevid));
	if (*groupMemberList == NULL) {
		ret = STMF_PS_ERROR_NOMEM;
		goto out;
	}

	i = 0;
	while ((scf_iter_next_value(valueIter, valueLookup) == 1) &&
	    (i < memberCnt)) {
		if ((len = scf_value_get_ustring(valueLookup, buf, MAXNAMELEN))
		    == -1) {
			syslog(LOG_ERR, "iter value %s/%s failed - %s",
			    pgName, groupName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}
		if (len < sizeof (stmfDevid) - 1) {
			(*groupMemberList)->name[i].identLength = len;
			bcopy(buf,
			    (*groupMemberList)->name[i++].ident, len);
			(*groupMemberList)->cnt++;
		} else {
			ret = STMF_PS_ERROR;
			break;
		}
	}

	if (ret != STMF_PS_SUCCESS) {
		free(*groupMemberList);
		goto out;
	}

out:
	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}
	if (prop != NULL) {
		scf_property_destroy(prop);
	}
	if (valueLookup != NULL) {
		scf_value_destroy(valueLookup);
	}
	if (valueIter != NULL) {
		scf_iter_destroy(valueIter);
	}

	return (ret);
}

int
psGetServicePersist(uint8_t *persistType)
{
	scf_handle_t	*handle = NULL;
	scf_service_t	*svc = NULL;
	int ret;

	if (iPsExtendedMode == B_TRUE) {
		if (persistType != NULL)
			*persistType = STMF_PERSIST_SMF;
		return STMF_PS_SUCCESS;
	}
	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		return (STMF_PS_ERROR);
	}

	ret = iPsGetSetPersistType(persistType, handle, svc, GET);

	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	return (ret);
}

int
psSetServicePersist(uint8_t persistType)
{
	scf_handle_t	*handle = NULL;
	scf_service_t	*svc = NULL;
	int ret;


	if (iPsExtendedMode == B_TRUE) {
		return STMF_PS_SUCCESS;
	}
	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		return (STMF_PS_ERROR);
	}

	ret = iPsGetSetPersistType(&persistType, handle, svc, SET);

	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	return (ret);
}

static int
iPsGetSetPersistType(uint8_t *persistType, scf_handle_t *handle,
    scf_service_t *svc, int getSet)
{
	scf_propertygroup_t	*pg = NULL;
	scf_property_t	*prop = NULL;
	scf_value_t	*value = NULL;
	scf_transaction_t *tran = NULL;
	scf_transaction_entry_t *entry = NULL;
	char iPersistTypeGet[MAXNAMELEN] = {0};
	char *iPersistType;
	int ret = STMF_PS_SUCCESS;
	int commitRet;

	if (((pg = scf_pg_create(handle)) == NULL) ||
	    ((prop = scf_property_create(handle)) == NULL) ||
	    ((entry = scf_entry_create(handle)) == NULL) ||
	    ((tran = scf_transaction_create(handle)) == NULL) ||
	    ((value = scf_value_create(handle)) == NULL)) {
		syslog(LOG_ERR, "scf alloc resource failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	if (getSet == GET) {
		/* set to default */
		*persistType = STMF_PERSIST_SMF;
		iPersistType = STMF_PS_PERSIST_SMF;
	}

	if (getSet == SET) {
		if (*persistType == STMF_PERSIST_SMF) {
			iPersistType = STMF_PS_PERSIST_SMF;
		} else if (*persistType == STMF_PERSIST_NONE) {
			iPersistType = STMF_PS_PERSIST_NONE;
		} else {
			ret = STMF_PS_ERROR;
			goto out;
		}
	}

	/*
	 * get stmf data property group
	 */
	if (scf_service_get_pg(svc, STMF_DATA_GROUP, pg) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND) {
			ret = STMF_PS_ERROR_NOT_FOUND;
		} else {
			ret = STMF_PS_ERROR;
		}
		syslog(LOG_ERR, "get pg %s failed - %s",
		    STMF_DATA_GROUP, scf_strerror(scf_error()));

		goto out;
	}

	/* find persistence property */
	/*
	 * Get the persistence property
	 */
	if (scf_pg_get_property(pg, STMF_PERSIST_TYPE, prop) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND) {
			ret = STMF_PS_ERROR_NOT_FOUND;
		} else {
			syslog(LOG_ERR, "get property %s/%s failed - %s",
			    STMF_DATA_GROUP, STMF_PERSIST_TYPE,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	}

	/* no persist property found */
	if (ret == STMF_PS_ERROR_NOT_FOUND || getSet == SET) {
		/*
		 * If we have no persistType property, go ahead
		 * and create it with the user specified value or
		 * the default value.
		 */
		/*
		 * Begin the transaction
		 */
		if (scf_transaction_start(tran, pg) == -1) {
			syslog(LOG_ERR, "start transaction for %s failed - %s",
			    STMF_DATA_GROUP, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/* is this a SET or GET w/error? */
		if (ret) {
			if (scf_transaction_property_new(tran, entry,
			    STMF_PERSIST_TYPE, SCF_TYPE_ASTRING) == -1) {
				syslog(LOG_ERR, "transaction property new "
				    "%s/%s failed - %s", STMF_DATA_GROUP,
				    STMF_PERSIST_TYPE,
				    scf_strerror(scf_error()));
				ret = STMF_PS_ERROR;
				goto out;
			}
		} else {
			if (scf_transaction_property_change(tran, entry,
			    STMF_PERSIST_TYPE, SCF_TYPE_ASTRING) == -1) {
				syslog(LOG_ERR, "transaction property change "
				    "%s/%s failed - %s", STMF_DATA_GROUP,
				    STMF_PERSIST_TYPE,
				    scf_strerror(scf_error()));
				ret = STMF_PS_ERROR;
				goto out;
			}
		}

		/*
		 * set the persist type
		 */
		if (scf_value_set_astring(value, iPersistType) == -1) {
			syslog(LOG_ERR, "set value %s/%s failed - %s",
			    STMF_DATA_GROUP, STMF_PERSIST_TYPE,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/*
		 * add the value to the transaction
		 */
		if (scf_entry_add_value(entry, value) == -1) {
			syslog(LOG_ERR, "add value %s/%s failed - %s",
			    STMF_DATA_GROUP, STMF_PERSIST_TYPE,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
		if ((commitRet = scf_transaction_commit(tran)) != 1) {
			syslog(LOG_ERR, "transaction commit for %s failed - %s",
			    STMF_DATA_GROUP, scf_strerror(scf_error()));
			if (commitRet == 0) {
				ret = STMF_PS_ERROR_BUSY;
			} else {
				ret = STMF_PS_ERROR;
			}
			goto out;
		}
		/* reset return value */
		ret = STMF_PS_SUCCESS;
	} else if (getSet == GET) {
		/* get the persist property */
		if (scf_property_get_value(prop, value) == -1) {
			syslog(LOG_ERR, "get property value %s/%s failed - %s",
			    STMF_DATA_GROUP, STMF_PERSIST_TYPE,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/*
		 * Get the value of the persist property
		 */
		if (scf_value_get_astring(value, iPersistTypeGet, MAXNAMELEN)
		    == -1) {
			syslog(LOG_ERR, "get string value %s/%s failed - %s",
			    STMF_DATA_GROUP, STMF_PERSIST_TYPE,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	}

	if (getSet == GET) {
		if (strcmp(iPersistTypeGet, STMF_PS_PERSIST_NONE) == 0) {
			*persistType = STMF_PERSIST_NONE;
		} else if (strcmp(iPersistTypeGet, STMF_PS_PERSIST_SMF) == 0) {
			*persistType = STMF_PERSIST_SMF;
		} else {
			ret = STMF_PS_ERROR;
			goto out;
		}
	}
out:
	/*
	 * Free resources.
	 * handle and svc should not be free'd here. They're
	 * free'd elsewhere
	 */
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}
	if (prop != NULL) {
		scf_property_destroy(prop);
	}
	if (entry != NULL) {
		scf_entry_destroy(entry);
	}
	if (tran != NULL) {
		scf_transaction_destroy(tran);
	}
	if (value != NULL) {
		scf_value_destroy(value);
	}
	return (ret);
}

int
psSetStmfProp(int propType, char *propVal)
{
	return (iPsGetSetStmfProp(propType, propVal, SET));
}

int
psGetStmfProp(int propType, char *propVal)
{
	return (iPsGetSetStmfProp(propType, propVal, GET));
}

static int
iPsGetSetStmfProp(int propType, char *propVal, int getSet)
{
	scf_handle_t	*handle = NULL;
	scf_service_t	*svc = NULL;
	scf_property_t *prop = NULL;
	scf_propertygroup_t	*pg = NULL;
	scf_transaction_t *tran = NULL;
	scf_transaction_entry_t *entry = NULL;
	scf_value_t	*value = NULL;
	char *psStmfPropVal = NULL;
	char *psStmfProp = NULL;
	char stmfPropGet[MAXNAMELEN] = {0};
	int ret = STMF_PS_SUCCESS;
	int commitRet;

	if (propVal == NULL || (getSet != GET && getSet != SET)) {
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * Init the service handle
	 */

	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	/*
	 * Allocate scf resources
	 */

	if (((pg = scf_pg_create(handle)) == NULL) ||
	    ((prop = scf_property_create(handle)) == NULL) ||
	    ((entry = scf_entry_create(handle)) == NULL) ||
	    ((tran = scf_transaction_create(handle)) == NULL) ||
	    ((value = scf_value_create(handle)) == NULL)) {
		syslog(LOG_ERR, "scf alloc resource failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}
	if (getSet == GET) {
		switch (propType) {
			case STMF_DEFAULT_LU_STATE :
				psStmfProp = DEFAULT_LU_STATE;
				psStmfPropVal = STMF_PS_LU_ONLINE;
				(void) strcpy(stmfPropGet, psStmfPropVal);
				break;
			case STMF_DEFAULT_TARGET_PORT_STATE :
				psStmfProp = DEFAULT_TARGET_PORT_STATE;
				psStmfPropVal = STMF_PS_TARGET_PORT_ONLINE;
				(void) strcpy(stmfPropGet, psStmfPropVal);
				break;
			default :
				ret = STMF_PS_ERROR;
				goto out;
		}
	}
	if (getSet == SET) {
		switch (propType) {
			case STMF_DEFAULT_LU_STATE :
				psStmfProp = DEFAULT_LU_STATE;
				if (strcasecmp(propVal, "online") == 0) {
					psStmfPropVal = STMF_PS_LU_ONLINE;
				} else if (strcasecmp(propVal,
				    "offline") == 0) {
					psStmfPropVal = STMF_PS_LU_OFFLINE;
				} else {
					ret = STMF_PS_ERROR;
					goto out;
				}
				break;
			case STMF_DEFAULT_TARGET_PORT_STATE :
				psStmfProp = DEFAULT_TARGET_PORT_STATE;
				if (strcasecmp(propVal, "online") == 0) {
					psStmfPropVal =
					    STMF_PS_TARGET_PORT_ONLINE;
				} else if (strcasecmp(propVal,
				    "offline") == 0) {
					psStmfPropVal =
					    STMF_PS_TARGET_PORT_OFFLINE;
				} else {
					ret = STMF_PS_ERROR;
					goto out;
				}
				break;
			default :
				ret = STMF_PS_ERROR;
				goto out;
		}
	}

	/*
	 * get stmf data property group
	 */

	if (scf_service_get_pg(svc, STMF_DATA_GROUP, pg) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND) {
			ret = STMF_PS_ERROR_NOT_FOUND;
		} else {
			ret = STMF_PS_ERROR;
		}
		syslog(LOG_ERR, "get pg %s failed - %s",
		    STMF_DATA_GROUP, scf_strerror(scf_error()));
		goto out;
	}

	/*
	 * get the stmf props property, if exists
	 */

	if (scf_pg_get_property(pg, psStmfProp, prop) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND) {
			ret = STMF_PS_ERROR_NOT_FOUND;
		} else {
			syslog(LOG_ERR, "start transaction for %s/%s "
			    "failed - %s", STMF_DATA_GROUP, psStmfProp,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	}

	/* if stmf prop is not found or while setting the prop */

	if (ret == STMF_PS_ERROR_NOT_FOUND || getSet == SET) {
		/*
		 * Begin the transaction
		 */
		if (scf_transaction_start(tran, pg) == -1) {
			syslog(LOG_ERR, "start transaction for %s failed - %s",
			    STMF_DATA_GROUP, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
		if (ret) {
			if (scf_transaction_property_new(tran, entry,
			    psStmfProp, SCF_TYPE_ASTRING) == -1) {
				syslog(LOG_ERR, "transaction property new "
				    "%s/%s failed - %s", STMF_DATA_GROUP,
				    psStmfProp, scf_strerror(scf_error()));
				ret = STMF_PS_ERROR;
				goto out;
			}
		} else {
			if (scf_transaction_property_change(tran, entry,
			    psStmfProp, SCF_TYPE_ASTRING) == -1) {
					syslog(LOG_ERR,
					    "transaction property change "
					    "%s/%s failed - %s",
					    STMF_DATA_GROUP, psStmfProp,
					    scf_strerror(scf_error()));
					ret = STMF_PS_ERROR;
					goto out;
			}
		}

		/*
		 * set stmf prop value
		 */

		if (scf_value_set_astring(value, psStmfPropVal) == -1) {
			syslog(LOG_ERR, "set value %s/%s failed - %s",
			    STMF_DATA_GROUP, psStmfProp,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/*
		 * add the value to the transaction
		 */

		if (scf_entry_add_value(entry, value) == -1) {
			syslog(LOG_ERR, "add value %s/%s failed - %s",
			    STMF_DATA_GROUP, psStmfProp,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
		if ((commitRet = scf_transaction_commit(tran)) != 1) {
			syslog(LOG_ERR, "transaction commit for %s"
			    "failed - %s", STMF_DATA_GROUP,
			    scf_strerror(scf_error()));
			if (commitRet == 0) {
				ret = STMF_PS_ERROR_BUSY;
			} else {
				ret = STMF_PS_ERROR;
			}
			goto out;
		}
		ret = STMF_PS_SUCCESS;
	} else if (getSet == GET) {
		if (scf_property_get_value(prop, value) == -1) {
			syslog(LOG_ERR, "get property value "
			    "%s/%s failed - %s",
			    STMF_DATA_GROUP, psStmfProp,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/* get stmfProp */

		if (scf_value_get_astring(value, stmfPropGet, MAXNAMELEN)
		    == -1) {
			syslog(LOG_ERR, "get string value %s/%s failed - %s",
			    STMF_DATA_GROUP, psStmfProp,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	}
	if (getSet == GET) {
		if (strcmp(stmfPropGet, STMF_PS_LU_ONLINE) == 0) {
			(void) strcpy(propVal, "online");
		} else if (strcmp(stmfPropGet, STMF_PS_LU_OFFLINE) == 0) {
			(void) strcpy(propVal, "offline");
		} else if (strcmp(stmfPropGet, STMF_PS_TARGET_PORT_ONLINE)
		    == 0) {
			(void) strcpy(propVal, "online");
		} else if (strcmp(stmfPropGet, STMF_PS_TARGET_PORT_OFFLINE)
		    == 0) {
			(void) strcpy(propVal, "offline");
		} else {
			ret = STMF_PS_ERROR;
			goto out;
		}
	}
out:
	/*
	 * Free resources.
	 */

	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}
	if (prop != NULL) {
		scf_property_destroy(prop);
	}
	if (entry != NULL) {
		scf_entry_destroy(entry);
	}
	if (tran != NULL) {
		scf_transaction_destroy(tran);
	}
	if (value != NULL) {
		scf_value_destroy(value);
	}
	return (ret);
}

/*
 * Initialize scf stmf service access
 * handle - returned handle
 * service - returned service handle
 *
 * Both handle and service must be destroyed by the caller
 */
static int
iPsInit(scf_handle_t **handle, scf_service_t **service)
{
	scf_scope_t	*scope = NULL;
	uint64_t version;
	int ret;

	assert(handle != NULL && service != NULL);

	if ((*handle = scf_handle_create(SCF_VERSION)) == NULL) {
		syslog(LOG_ERR, "scf_handle_create failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto err;
	}

	if (scf_handle_bind(*handle) == -1) {
		syslog(LOG_ERR, "scf_handle_bind failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto err;
	}

	if ((*service = scf_service_create(*handle)) == NULL) {
		syslog(LOG_ERR, "scf_service_create failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto err;
	}

	if ((scope = scf_scope_create(*handle)) == NULL) {
		syslog(LOG_ERR, "scf_scope_create failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto err;
	}

	if (scf_handle_get_scope(*handle, SCF_SCOPE_LOCAL, scope) == -1) {
		syslog(LOG_ERR, "scf_handle_get_scope failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto err;
	}

#ifdef	__dilos__
	char	svc_name[4096];

	if (stmfServiceName(svc_name, sizeof(svc_name)) != svc_name) {
		strlcpy(svc_name, STMF_SERVICE, sizeof(svc_name));
		syslog(LOG_ERR, "no stmf service file defined, "
			"use default name %s", svc_name);
	}
	if (scf_scope_get_service(scope, svc_name, *service) == -1) {
#else	/* !__dilos__ */
	if (scf_scope_get_service(scope, STMF_SERVICE, *service) == -1) {
#endif	/* __dilos__ */

		syslog(LOG_ERR, "scf_scope_get_service failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR_SERVICE_NOT_FOUND;
		goto err;
	}


	/*
	 * Get and check the version number
	 */
	ret = iPsGetServiceVersion(&version, *handle, *service);
	if (ret != STMF_PS_SUCCESS) {
		goto err;
	}

	if (version != STMF_SMF_VERSION) {
		ret = STMF_PS_ERROR_VERSION_MISMATCH;
		goto err;
	}

	/* we only need destroy the scope here */
	scf_scope_destroy(scope);

	return (STMF_PS_SUCCESS);

err:
	if (*handle != NULL) {
		scf_handle_destroy(*handle);
	}
	if (*service != NULL) {
		scf_service_destroy(*service);
		*service = NULL;
	}
	if (scope != NULL) {
		scf_scope_destroy(scope);
	}
	return (ret);
}


/*
 * called by iPsInit only
 * iPsGetServiceVersion
 */
static int
iPsGetServiceVersion(uint64_t *version, scf_handle_t *handle,
    scf_service_t *svc)
{
	scf_propertygroup_t	*pg = NULL;
	scf_property_t	*prop = NULL;
	scf_value_t	*value = NULL;
	scf_transaction_t *tran = NULL;
	scf_transaction_entry_t *entry = NULL;
	int ret = STMF_PS_SUCCESS;
	int commitRet;

	if (((pg = scf_pg_create(handle)) == NULL) ||
	    ((prop = scf_property_create(handle)) == NULL) ||
	    ((entry = scf_entry_create(handle)) == NULL) ||
	    ((tran = scf_transaction_create(handle)) == NULL) ||
	    ((value = scf_value_create(handle)) == NULL)) {
		syslog(LOG_ERR, "scf alloc resource failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	*version = STMF_SMF_VERSION;

	/*
	 * get stmf data property group
	 */
	if (scf_service_get_pg(svc, STMF_DATA_GROUP, pg) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND) {
			ret = STMF_PS_ERROR_NOT_FOUND;
		} else {
			syslog(LOG_ERR, "get pg %s failed - %s",
			    STMF_DATA_GROUP, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	}

	/* create the group */
	if (ret == STMF_PS_ERROR_NOT_FOUND) {
		/*
		 * create the property group.
		 */
		if (scf_service_add_pg(svc, STMF_DATA_GROUP,
		    SCF_GROUP_APPLICATION, 0, pg) == -1) {
			syslog(LOG_ERR, "add pg %s failed - %s",
			    STMF_DATA_GROUP, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
		/* reset return value */
		ret = STMF_PS_SUCCESS;
	}

	/* find version property */
	/*
	 * Get the version property
	 */
	if (scf_pg_get_property(pg, STMF_VERSION_NAME, prop) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND) {
			ret = STMF_PS_ERROR_NOT_FOUND;
		} else {
			syslog(LOG_ERR, "get property %s/%s failed - %s",
			    STMF_DATA_GROUP, STMF_VERSION_NAME,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	}

	/* no version property found */
	if (ret == STMF_PS_ERROR_NOT_FOUND) {
		/*
		 * If we have no version property, go ahead
		 * and create it. We're obviously making an assumption
		 * here that someone did not delete the existing property
		 * and that this is the initial set and the initial call
		 * to iPsInit.
		 * If they did delete it, this will simply plant this
		 * library's version on this service. That may or may not be
		 * correct and we have no way of determining that.
		 */
		/*
		 * Begin the transaction
		 */
		if (scf_transaction_start(tran, pg) == -1) {
			syslog(LOG_ERR, "start transaction for %s failed - %s",
			    STMF_DATA_GROUP, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		if (scf_transaction_property_new(tran, entry,
		    STMF_VERSION_NAME, SCF_TYPE_COUNT) == -1) {
			syslog(LOG_ERR,
			    "transaction property new %s/%s failed - %s",
			    STMF_DATA_GROUP, STMF_VERSION_NAME,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/*
		 * set the version number
		 */
		scf_value_set_count(value, *version);

		/*
		 * add the value to the transaction
		 */
		if (scf_entry_add_value(entry, value) == -1) {
			syslog(LOG_ERR, "add value %s/%s failed - %s",
			    STMF_DATA_GROUP, STMF_VERSION_NAME,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
		if ((commitRet = scf_transaction_commit(tran)) != 1) {
			syslog(LOG_ERR, "transaction commit for %s failed - %s",
			    STMF_DATA_GROUP, scf_strerror(scf_error()));
			if (commitRet == 0) {
				ret = STMF_PS_ERROR_BUSY;
			} else {
				ret = STMF_PS_ERROR;
			}
			goto out;
		}
		/* reset return value */
		ret = STMF_PS_SUCCESS;
	} else {
		/* get the version property */
		if (scf_pg_get_property(pg, STMF_VERSION_NAME, prop) == -1) {
			syslog(LOG_ERR, "get property %s/%s failed - %s",
			    STMF_DATA_GROUP, STMF_VERSION_NAME,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		if (scf_property_get_value(prop, value) == -1) {
			syslog(LOG_ERR, "get property value %s/%s failed - %s",
			    STMF_DATA_GROUP, STMF_VERSION_NAME,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/*
		 * Get the actual value of the view entry count property
		 */
		if (scf_value_get_count(value, version) == -1) {
			syslog(LOG_ERR, "get count value %s/%s failed - %s",
			    STMF_DATA_GROUP, STMF_VERSION_NAME,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	}

out:
	/*
	 * Free resources.
	 * handle and svc should not be free'd here. They're
	 * free'd elsewhere
	 */
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}
	if (prop != NULL) {
		scf_property_destroy(prop);
	}
	if (entry != NULL) {
		scf_entry_destroy(entry);
	}
	if (tran != NULL) {
		scf_transaction_destroy(tran);
	}
	if (value != NULL) {
		scf_value_destroy(value);
	}
	return (ret);
}



/*
 * iPsGetActualGroupName
 *
 * pgName - Property group name
 * groupName - requested group name
 * actualName - actual group name to reference (len must be >= MAXNAMELEN)
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
static int
iPsGetActualGroupName(char *pgName, char *groupName, char *actualName)
{
	scf_handle_t	*handle = NULL;
	scf_service_t	*svc = NULL;
	scf_propertygroup_t	*pg = NULL;
	scf_property_t	*prop = NULL;
	scf_iter_t	*propIter = NULL;
	scf_value_t	*value = NULL;
	char buf[MAXNAMELEN];
	int ret;

	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	/*
	 * Allocate scf resources
	 */
	if (((pg = scf_pg_create(handle)) == NULL) ||
	    ((prop = scf_property_create(handle)) == NULL) ||
	    ((propIter = scf_iter_create(handle)) == NULL) ||
	    ((value = scf_value_create(handle)) == NULL)) {
		syslog(LOG_ERR, "scf alloc resource failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * get group list property group
	 */
	if (scf_service_get_pg(svc, pgName, pg) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND) {
			ret = STMF_PS_ERROR_GROUP_NOT_FOUND;
		} else {
			syslog(LOG_ERR, "get pg %s failed - %s",
			    pgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
		}
		goto out;
	}

	/*
	 * propIter is the iterator handle
	 */
	if (scf_iter_pg_properties(propIter, pg) == -1) {
		syslog(LOG_ERR, "iter properties for %s failed - %s",
		    pgName, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * Iterate through group properties searching for the requested
	 * group name. When we find it, we need to get the property name
	 * since it refers to the actual group name.
	 */

	/* initialize to not found */
	ret = STMF_PS_ERROR_GROUP_NOT_FOUND;
	while (scf_iter_next_property(propIter, prop) == 1) {
		if (scf_property_get_name(prop, actualName, MAXNAMELEN) == -1) {
			syslog(LOG_ERR, "get name from %s iter failed - %s",
			    pgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}
		/*
		 * Skip over non-member list properties
		 */
		if (strstr(actualName, STMF_MEMBER_LIST_SUFFIX)) {
			continue;
		}
		if (scf_property_get_value(prop, value) == -1) {
			syslog(LOG_ERR, "get property value %s/%s failed - %s",
			    pgName, actualName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}
		if (scf_value_get_ustring(value, buf, sizeof (buf)) == -1) {
			syslog(LOG_ERR, "get ustring %s/%s failed - %s",
			    pgName, actualName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}

		/*
		 * When we find a match, set success and break
		 */
		if ((strlen(buf) == strlen(groupName)) &&
		    bcmp(buf, groupName, strlen(buf)) == 0) {
			ret = STMF_PS_SUCCESS;
			break;
		}
	}

	/*
	 * if we didn't find it, ret is set to STMF_PS_ERROR_GROUP_NOT_FOUND
	 */

out:
	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}
	if (propIter != NULL) {
		scf_iter_destroy(propIter);
	}
	if (prop != NULL) {
		scf_property_destroy(prop);
	}
	if (value != NULL) {
		scf_value_destroy(value);
	}

	return (ret);
}

/*
 * psAddHostGroupMember
 *
 * Add a host group member to a host group,
 *
 * Input: groupName - name of group to which the member is added
 *        memberName - name of group member to add
 */
int
psAddHostGroupMember(char *groupName, char *memberName)
{
    int ret;
    char groupPropListName[MAXNAMELEN];
    char groupPropName[MAXNAMELEN];

    if (iPsExtendedMode == B_TRUE) {
        ret = iPsGetActualGroupNameExt(STMF_HOST_GROUPS, groupName,
                                       groupPropName);
    }
    else {
        ret = iPsGetActualGroupName(STMF_HOST_GROUPS, groupName, groupPropName);
    }
    if (ret != STMF_PS_SUCCESS) {
        return (ret);
    }

    if (snprintf(groupPropListName, sizeof (groupPropListName),
        "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
        sizeof (groupPropListName)) {
        syslog(LOG_ERR, "buffer overflow on property name %s",
               groupPropName);
        return (STMF_PS_ERROR);
    }

    if (iPsExtendedMode == B_TRUE) {
        return (iPsAddGroupMemberExt(STMF_HOST_GROUPS, groupPropName,
                memberName));
    }
    return (iPsAddRemoveGroupMember(STMF_HOST_GROUPS, groupPropListName,
            memberName, ADD));
}

/*
 * psAddTargetGroupMember
 *
 * Add a target port group member to a target group
 *
 * Input: groupName - name of group to which the member is added
 *        memberName - name of group member to add. Must be nul terminated.
 */
int
psAddTargetGroupMember(char *groupName, char *memberName)
{
    int ret;
    char groupPropListName[MAXNAMELEN];
    char groupPropName[MAXNAMELEN];

    if (iPsExtendedMode == B_TRUE) {
        ret = iPsGetActualGroupNameExt(STMF_TARGET_GROUPS, groupName,
                                       groupPropName);
    }
    else {
        ret = iPsGetActualGroupName(STMF_TARGET_GROUPS, groupName,
                                    groupPropName);
    }
    if (ret != STMF_PS_SUCCESS) {
        return (ret);
    }

    if (snprintf(groupPropListName, sizeof (groupPropListName),
        "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
        sizeof (groupPropListName)) {
        syslog(LOG_ERR, "buffer overflow on property name %s",
            groupPropName);
        return (STMF_PS_ERROR);
    }

    if (iPsExtendedMode == B_TRUE) {
        return (iPsAddGroupMemberExt(STMF_TARGET_GROUPS, groupPropName,
                memberName));
    }
    return (iPsAddRemoveGroupMember(STMF_TARGET_GROUPS, groupPropListName,
            memberName, ADD));
}


/*
 * psAddViewEntry
 *
 * luGuid - logical unit identifier
 * viewEntry - pointer to viewEntry allocated by the caller that contains
 *             the values to set for this view entry
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
int
psAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry)
{
    scf_handle_t    *handle = NULL;
    scf_service_t    *svc = NULL;
    scf_propertygroup_t    *pg = NULL;
    char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
    char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
    char scfLuPgName[LOGICAL_UNIT_PG_SIZE];
    int ret = STMF_PS_SUCCESS;
    sigset_t sigmaskRestore;

    /* grab the signal hold lock */
    (void) pthread_mutex_lock(&sigSetLock);

    /*
     * hold signals until we're done
     */
    if (holdSignal(&sigmaskRestore) != 0) {
        (void) pthread_mutex_unlock(&sigSetLock);
        return (STMF_PS_ERROR);
    }

    if (iPsExtendedMode == B_TRUE) {
        ret = iPsAddViewEntryExt(lu, viewEntry);
        goto out;
    }
    ret = iPsInit(&handle, &svc);
    if (ret != STMF_PS_SUCCESS) {
        goto out;
    }

    pg = scf_pg_create(handle);
    if (pg == NULL) {
        syslog(LOG_ERR, "scf pg alloc failed - %s", scf_strerror(scf_error()));
        ret = STMF_PS_ERROR;
        goto out;
    }

    /* Convert to ASCII uppercase hexadecimal string */
    (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
        "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
        lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
        lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
        lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
        lu->guid[14], lu->guid[15]);

    (void) snprintf(scfLuPgName, sizeof (scfLuPgName), "%s-%s", STMF_LU_PREFIX,
                    guidAsciiBuf);

    bzero(viewEntryPgName, sizeof (viewEntryPgName));
    /*
     * Format of view entry property group name:
     *    VE-<view_entry_name>-<lu_name>
     */
    (void) snprintf(viewEntryPgName, sizeof (viewEntryPgName),
        "%s-%d-%s", STMF_VE_PREFIX, viewEntry->veIndex, guidAsciiBuf);

    ret = iPsAddViewEntry(scfLuPgName, viewEntryPgName, viewEntry);

out:
    /*
     * Okay, we're done. Release the signals
     */
    if (releaseSignal(&sigmaskRestore) != 0) {
        /*
         * Don't set this as an STMF_PS_ERROR_*. We succeeded
         * the requested operation. But we do need to log it.
         */
        syslog(LOG_ERR, "Unable to release one or more signals - %s",
            strerror(errno));
    }

    /*
     * Free resources
     */
    if (handle != NULL) {
        scf_handle_destroy(handle);
    }
    if (svc != NULL) {
        scf_service_destroy(svc);
    }
    if (pg != NULL) {
        scf_pg_destroy(pg);
    }

    /* release the signal hold lock */
    (void) pthread_mutex_unlock(&sigSetLock);

    return (ret);
}

/*
 * psCheckService
 *
 * Purpose: Checks whether service exists
 *
 */
int
psCheckService()
{
	int ret;
	scf_handle_t	*handle = NULL;
	scf_service_t	*svc = NULL;

	ret = iPsInit(&handle, &svc);

	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}

	return (ret);
}

/*
 * psCreateHostGroup
 *
 * groupName - name of group to create
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
int
psCreateHostGroup(char *groupName)
{
	if (iPsExtendedMode == B_TRUE) {
		return iPsCreateGroupExt(STMF_HOST_GROUPS, groupName);
	}
	return (iPsCreateDeleteGroup(STMF_HOST_GROUPS, groupName, ADD));
}

/*
 * psCreateTargetGroup
 *
 * groupName - name of group to create
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
int
psCreateTargetGroup(char *groupName)
{
    if (iPsExtendedMode == B_TRUE) {
        return iPsCreateGroupExt(STMF_TARGET_GROUPS, groupName);
    }
    return (iPsCreateDeleteGroup(STMF_TARGET_GROUPS, groupName, ADD));
}

/*
 * psClearHostGroups
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
int
psClearHostGroups(void)
{
    if (iPsExtendedMode == B_TRUE) {
        return iPsClearGroupsExt(STMF_HOST_GROUPS);
    }
    return (iPsClearGroups(STMF_HOST_GROUPS));
}

/*
 * psClearTargetGroups
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
int
psClearTargetGroups(void)
{
    if (iPsExtendedMode == B_TRUE) {
        return iPsClearGroupsExt(STMF_TARGET_GROUPS);
    }
    return (iPsClearGroups(STMF_TARGET_GROUPS));
}

/*
 * psDeleteHostGroup
 *
 * groupName - name of group to delete
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
int
psDeleteHostGroup(char *groupName)
{
    if (iPsExtendedMode == B_TRUE) {
        return iPsDeleteGroupExt(STMF_HOST_GROUPS, groupName);
    }
    return (iPsCreateDeleteGroup(STMF_HOST_GROUPS, groupName, REMOVE));
}

/*
 * psDeleteTargetGroup
 *
 * groupName - name of group to delete
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
int
psDeleteTargetGroup(char *groupName)
{
    if (iPsExtendedMode == B_TRUE) {
        return iPsDeleteGroupExt(STMF_TARGET_GROUPS, groupName);
    }
    return (iPsCreateDeleteGroup(STMF_TARGET_GROUPS, groupName, REMOVE));
}

/*
 * psGetHostGroupList
 *
 * groupList - pointer to pointer to stmfGroupList. Contains the list
 *             of host groups on successful return.
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
int
psGetHostGroupList(stmfGroupList **groupList)
{
    if (iPsExtendedMode == B_TRUE) {
        return iPsGetGroupListExt(STMF_HOST_GROUPS, groupList);
    }
    return (iPsGetGroupList(STMF_HOST_GROUPS, groupList));
}

/*
 * psGetLogicalUnitList
 *
 *
 */
int
psGetLogicalUnitList(stmfGuidList **guidList)
{
	scf_handle_t	*handle = NULL;
	scf_service_t	*svc = NULL;
	scf_propertygroup_t	*pg = NULL;
	scf_iter_t	*pgIter = NULL;
	char buf[MAXNAMELEN];
	int guidCnt = 0;
	int i = 0, j;
	int ret = STMF_PS_SUCCESS;
	unsigned int guid[sizeof (stmfGuid)];
	stmfGuid outGuid;

	assert(guidList != NULL);

    if (iPsExtendedMode == B_TRUE) {
        nvlist_t *nvl = NULL;

        ret = iPsGetLogicalUnitListExt(&nvl, &guidCnt);
        if (ret != STMF_PS_SUCCESS) {
            return ret;
        }
        *guidList = (stmfGuidList *)calloc(1, sizeof(stmfGuidList)
                                           + guidCnt*sizeof(stmfGuid));
        if (*guidList == NULL) {
            return STMF_PS_ERROR_NOMEM;
        }
        iPsFromNvlToStmfLuListExt(*nvl, *guidList, guidCnt);
        return STMF_PS_SUCCESS;
    }

	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	/*
	 * Allocate scf resources
	 */
	if (((pg = scf_pg_create(handle)) == NULL) ||
	    ((pgIter = scf_iter_create(handle)) == NULL)) {
		syslog(LOG_ERR, "scf alloc resource failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * pgIter is the iterator handle
	 */
	if (scf_iter_service_pgs(pgIter, svc) == -1) {
		syslog(LOG_ERR, "iter property groups failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	while (scf_iter_next_pg(pgIter, pg) == 1) {
		if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
			syslog(LOG_ERR, "get pg name failed - %s",
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}
		/*
		 * Only count LU property groups
		 */
		if (strncmp(buf, STMF_LU_PREFIX, strlen(STMF_LU_PREFIX)) == 0) {
			guidCnt++;
		}
	}

	/*
	 * pgIter is the iterator handle
	 */
	if (scf_iter_service_pgs(pgIter, svc) == -1) {
		syslog(LOG_ERR, "iter property groups failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	*guidList = (stmfGuidList *)calloc(1, sizeof (stmfGuidList) +
	    guidCnt * sizeof (stmfGuid));
	if (*guidList == NULL) {
		ret = STMF_PS_ERROR_NOMEM;
		goto out;
	}

	/*
	 * it's possible for entries to be added/removed while we're retrieving
	 * the property groups. Just make sure we don't write beyond our
	 * allocated buffer by checking to ensure i < guidCnt.
	 */
	while ((scf_iter_next_pg(pgIter, pg) == 1) && (i < guidCnt)) {
		if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
			syslog(LOG_ERR, "get pg name failed - %s",
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}
		/*
		 * Only use LU property groups
		 */
		if (strncmp(buf, STMF_LU_PREFIX, strlen(STMF_LU_PREFIX)) != 0) {
			continue;
		}

		j = strlen(STMF_LU_PREFIX) + strlen("-");

		(void) sscanf(buf + j,
		    "%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X",
		    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
		    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10],
		    &guid[11], &guid[12], &guid[13], &guid[14], &guid[15]);

		for (j = 0; j < sizeof (stmfGuid); j++) {
			outGuid.guid[j] = guid[j];
		}

		bcopy(&outGuid, (*guidList)->guid[i++].guid, sizeof (stmfGuid));
		(*guidList)->cnt++;
	}

	if (ret != STMF_PS_SUCCESS) {
		free(*guidList);
		goto out;
	}

out:
	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}
	if (pgIter != NULL) {
		scf_iter_destroy(pgIter);
	}

	return (ret);
}

/*
 * psGetTargetGroupList
 *
 * groupList - pointer to pointer to stmfGroupList. Contains the list
 *             of target groups on successful return.
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
int
psGetTargetGroupList(stmfGroupList **groupList)
{
    if (iPsExtendedMode == B_TRUE) {
        return iPsGetGroupListExt(STMF_TARGET_GROUPS, groupList);
    }
    return (iPsGetGroupList(STMF_TARGET_GROUPS, groupList));
}

/*
 * psGetHostGroupMemberList
 *
 * groupName - group name for which to retrieve a member list
 * groupMemberList - pointer to pointer to stmfGroupProperties list
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
int
psGetHostGroupMemberList(char *groupName, stmfGroupProperties **groupMemberList)
{
    int ret;
    char groupPropListName[MAXNAMELEN];
    char groupPropName[MAXNAMELEN];

    if (iPsExtendedMode == B_TRUE) {
        ret = iPsGetActualGroupNameExt(STMF_HOST_GROUPS, groupName,
                                       groupPropName);
    }
    else {
        ret = iPsGetActualGroupName(STMF_HOST_GROUPS, groupName, groupPropName);
    }
    if (ret != STMF_PS_SUCCESS) {
        return (ret);
    }

    if (snprintf(groupPropListName, sizeof(groupPropListName),"%s-%s",
                 groupPropName, STMF_MEMBER_LIST_SUFFIX)
        > sizeof (groupPropListName)) {
        syslog(LOG_ERR, "buffer overflow on property name %s", groupPropName);
        return (STMF_PS_ERROR);
    }

    if (iPsExtendedMode == B_TRUE) {
        return iPsGetGroupMemberListExt(STMF_HOST_GROUPS, groupPropName,
                                        groupMemberList);
    }
    return (iPsGetGroupMemberList(STMF_HOST_GROUPS, groupPropListName,
                                  groupMemberList));
}

/*
 * psGetTargetGroupMemberList
 *
 * groupName - group name for which to retrieve a member list
 * groupMemberList - pointer to pointer to stmfGroupProperties list
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
int
psGetTargetGroupMemberList(char *groupName,
                           stmfGroupProperties **groupMemberList)
{
    int ret;
    char groupPropListName[MAXNAMELEN];
    char groupPropName[MAXNAMELEN];

    if (iPsExtendedMode == B_TRUE) {
        ret = iPsGetActualGroupNameExt(STMF_TARGET_GROUPS, groupName,
                                       groupPropName);
    }
    else {
          ret = iPsGetActualGroupName(STMF_TARGET_GROUPS, groupName,
                                      groupPropName);
    }
    if (ret != STMF_PS_SUCCESS) {
        return (ret);
    }

    if (snprintf(groupPropListName, sizeof(groupPropListName), "%s-%s",
                 groupPropName, STMF_MEMBER_LIST_SUFFIX)
        > sizeof (groupPropListName)) {
        syslog(LOG_ERR, "buffer overflow on property name %s", groupPropName);
        return (STMF_PS_ERROR);
    }

    if (iPsExtendedMode == B_TRUE) {
        return iPsGetGroupMemberListExt(STMF_TARGET_GROUPS, groupPropName,
                                        groupMemberList);
    }
    return (iPsGetGroupMemberList(STMF_TARGET_GROUPS, groupPropListName,
                                  groupMemberList));
}

/*
 * qsort function
 * sort on veIndex
 */
static int
viewEntryCompare(const void *p1, const void *p2)
{

	stmfViewEntry *v1 = (stmfViewEntry *)p1, *v2 = (stmfViewEntry *)p2;
	if (v1->veIndex > v2->veIndex)
		return (1);
	if (v1->veIndex < v2->veIndex)
		return (-1);
	return (0);
}

/*
 * psGetViewEntryList
 *
 * luGuid - identifier of logical unit for which to retrieve a view entry list
 * viewEntryList - pointer to pointer to stmfViewEntryList. It will be allocated
 *                 on successful return.
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
int
psGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList)
{
	scf_handle_t	*handle = NULL;
	scf_service_t	*svc = NULL;
	scf_propertygroup_t	*pg = NULL;
	scf_property_t	*prop = NULL;
	scf_value_t *value = NULL;
	scf_iter_t  *propIter = NULL;
	char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
	char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
	char luPgName[LOGICAL_UNIT_PG_SIZE];
	int ret = STMF_PS_SUCCESS;
	uint64_t i = 0;
	uint64_t veCnt = 0;


    if (iPsExtendedMode == B_TRUE) {
        nvlist_t *nvl = NULL;

        ret = iPsGetViewEntryListExt(lu, &nvl, &veCnt);
        if (ret != STMF_PS_SUCCESS) {
            return ret;
        }
        *viewEntryList = (stmfViewEntryList *)calloc(1, sizeof(stmfViewEntryList)
                                                  + veCnt*sizeof(stmfViewEntry));
        if (*viewEntryList == NULL) {
            return STMF_PS_ERROR_NOMEM;
        }
        iPsFromNvlToStmfVeListExt(*nvl, *viewEntryList, veCnt);
        qsort((void *)&((*viewEntryList)->ve[0]), (*viewEntryList)->cnt,
              sizeof(stmfViewEntry), viewEntryCompare);
        return STMF_PS_SUCCESS;
    }

	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	/*
	 * Allocate scf resources
	 */
	if (((pg = scf_pg_create(handle)) == NULL) ||
	    ((prop = scf_property_create(handle)) == NULL) ||
	    ((propIter = scf_iter_create(handle)) == NULL) ||
	    ((value = scf_value_create(handle)) == NULL)) {
		syslog(LOG_ERR, "scf alloc resource failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/* Convert to ASCII uppercase hexadecimal string */
	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
	    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
	    lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
	    lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
	    lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
	    lu->guid[14], lu->guid[15]);

	/* form the LU property group name (LU-<guid>) */
	(void) snprintf(luPgName, sizeof (luPgName), "%s-%s",
	    STMF_LU_PREFIX, guidAsciiBuf);

	/* get the property group associated with this LU */
	if (scf_service_get_pg(svc, luPgName, pg) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND) {
			ret = STMF_PS_ERROR_NOT_FOUND;
		} else {
			syslog(LOG_ERR, "get pg %s failed - %s",
			    luPgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
		}
		goto out;
	}

	/* get the view entry count property */
	if (scf_pg_get_property(pg, STMF_VE_CNT, prop) == -1) {
		syslog(LOG_ERR, "get property %s/%s failed - %s",
		    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	if (scf_property_get_value(prop, value) == -1) {
		syslog(LOG_ERR, "get property value %s/%s failed - %s",
		    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * Get the actual value of the view entry count property
	 */
	if (scf_value_get_count(value, &veCnt) == -1) {
		syslog(LOG_ERR, "get integer value %s/%s failed - %s",
		    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * propIter is the iterator handle
	 */
	if (scf_iter_pg_properties(propIter, pg) == -1) {
		syslog(LOG_ERR, "iter properties for %s failed - %s",
		    luPgName, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * alloc the list based on the view entry count
	 */
	*viewEntryList = (stmfViewEntryList *)calloc(1,
                     sizeof(stmfViewEntryList) + veCnt*sizeof(stmfViewEntry));
	if (*viewEntryList == NULL) {
		ret = STMF_PS_ERROR_NOMEM;
		goto out;
	}

	i = 0;
	/*
	 * iterate through the view entry properties to find the
	 * view entries
	 */
	while (scf_iter_next_property(propIter, prop) == 1) {
		/* find match for view entry property */
		if (scf_property_get_name(prop, viewEntryPgName,
		    sizeof (viewEntryPgName)) != -1) {
			if (strncmp(viewEntryPgName, STMF_VE_PREFIX,
			    strlen(STMF_VE_PREFIX)) != 0) {
				continue;
			}
			/*
			 * We've exceeded our alloc limit
			 * break with error
			 */
			if (i == veCnt) {
				ret = STMF_PS_ERROR;
				break;
			}

			if ((ret = iPsGetViewEntry(viewEntryPgName,
			    &((*viewEntryList)->ve[i]))) != STMF_PS_SUCCESS) {
				break;
			}

			i++;

			/* set the list count */
			(*viewEntryList)->cnt++;
		} else {
			syslog(LOG_ERR, "scf iter %s properties failed - %s",
			    luPgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}

	}

	if (ret != STMF_PS_SUCCESS) {
		free(*viewEntryList);
		*viewEntryList = NULL;
		goto out;
	}

	/*
	 * We're sorting the final list here based on the veIndex
	 * If we don't, the caller is going to have to do it to reap
	 * some intelligent output.
	 */
	qsort((void *)&((*viewEntryList)->ve[0]), (*viewEntryList)->cnt,
	    sizeof (stmfViewEntry), viewEntryCompare);

out:
	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}
	if (prop != NULL) {
		scf_property_destroy(prop);
	}
	if (value != NULL) {
		scf_value_destroy(value);
	}
	if (propIter != NULL) {
		scf_iter_destroy(propIter);
	}

	return (ret);
}

/*
 * iPsGetViewEntry
 *
 * viewEntryPgName - view entry property group name to retrieve
 * viewEntry - pointer to stmfViewEntry structure allocated by the caller
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
static int
iPsGetViewEntry(char *viewEntryPgName, stmfViewEntry *viewEntry)
{
	scf_handle_t	*handle = NULL;
	scf_service_t	*svc = NULL;
	scf_propertygroup_t	*pg = NULL;
	scf_property_t	*prop = NULL;
	scf_value_t *value = NULL;
	uint8_t scfBool;
	char *indexPtr;
	char groupName[sizeof (stmfGroupName)];
	int ret = STMF_PS_SUCCESS;

	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	/*
	 * Allocate scf resources
	 */
	if (((pg = scf_pg_create(handle)) == NULL) ||
	    ((prop = scf_property_create(handle)) == NULL) ||
	    ((value = scf_value_create(handle)) == NULL)) {
		syslog(LOG_ERR, "scf alloc resource failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	bzero(viewEntry, sizeof (stmfViewEntry));

	/*
	 * get the service property group view entry handle
	 */
	if (scf_service_get_pg(svc, viewEntryPgName, pg) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND) {
			ret = STMF_PS_ERROR_NOT_FOUND;
		} else {
			syslog(LOG_ERR, "get pg %s failed - %s",
			    viewEntryPgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
		}
		goto out;
	}


	/*
	 * get index
	 * format is: VE-<veIndex>-GUID
	 */
	indexPtr = strchr(viewEntryPgName, '-');
	if (!indexPtr) {
		ret = STMF_PS_ERROR;
		goto out;
	}

	/* Set the index */
	viewEntry->veIndex = atoi(strtok(++indexPtr, "-"));

	viewEntry->veIndexValid = B_TRUE;

	/* get allHosts property */
	if (scf_pg_get_property(pg, STMF_VE_ALLHOSTS,
	    prop) == -1) {
		syslog(LOG_ERR, "get property %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_ALLHOSTS,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	if (scf_property_get_value(prop, value) == -1) {
		syslog(LOG_ERR, "get property %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_ALLHOSTS,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/* set allHosts */
	if (scf_value_get_boolean(value, (uint8_t *)&scfBool) == -1) {
		syslog(LOG_ERR, "get property %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_ALLHOSTS,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}
	viewEntry->allHosts = scfBool;

	/* get hostGroup property */
	if (scf_pg_get_property(pg, STMF_VE_HOSTGROUP,
	    prop) == -1) {
		syslog(LOG_ERR, "get property %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_HOSTGROUP,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	if (scf_property_get_value(prop, value) == -1) {
		syslog(LOG_ERR, "get property %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_HOSTGROUP,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	if (scf_value_get_ustring(value, groupName,
	    sizeof (groupName)) == -1) {
		syslog(LOG_ERR, "get value %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_HOSTGROUP,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}
	/* set hostGroup */
	bcopy(groupName, viewEntry->hostGroup, strlen(groupName));

	/* get allTargets property */
	if (scf_pg_get_property(pg, STMF_VE_ALLTARGETS,
	    prop) == -1) {
		syslog(LOG_ERR, "get property %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_ALLTARGETS,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	if (scf_property_get_value(prop, value) == -1) {
		syslog(LOG_ERR, "get property value %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_ALLTARGETS,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/* set allTargets */
	if (scf_value_get_boolean(value, (uint8_t *)&scfBool) == -1) {
		syslog(LOG_ERR, "get value %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_ALLTARGETS,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}
	viewEntry->allTargets = scfBool;

	/* get targetGroup property */
	if (scf_pg_get_property(pg, STMF_VE_TARGETGROUP, prop) == -1) {
		syslog(LOG_ERR, "get property %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_TARGETGROUP,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	if (scf_property_get_value(prop, value) == -1) {
		syslog(LOG_ERR, "get property value %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_TARGETGROUP,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	if (scf_value_get_ustring(value, groupName,
	    sizeof (groupName)) == -1) {
		syslog(LOG_ERR, "get value %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_TARGETGROUP,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}
	/* set targetGroup */
	bcopy(groupName, viewEntry->targetGroup, strlen(groupName));

	/* get luNbr property */
	if (scf_pg_get_property(pg, STMF_VE_LUNBR,
	    prop) == -1) {
		syslog(LOG_ERR, "get property %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_LUNBR,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	if (scf_property_get_value(prop, value) == -1) {
		syslog(LOG_ERR, "get property value %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_LUNBR,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/* set luNbr */
	if (scf_value_get_opaque(value, (char *)viewEntry->luNbr,
	    sizeof (viewEntry->luNbr)) == -1) {
		syslog(LOG_ERR, "get opaque value %s/%s failed - %s",
		    viewEntryPgName, STMF_VE_LUNBR,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}
	/* set luNbrValid to true since we just got it */
	viewEntry->luNbrValid = B_TRUE;

out:
	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}
	if (value != NULL) {
		scf_value_destroy(value);
	}
	if (prop != NULL) {
		scf_property_destroy(prop);
	}

	return (ret);
}


/*
 * psRemoveHostGroupMember
 *
 * Remove a host group member from a host group,
 *
 * groupName - name of group from which the member is removed
 * memberName - name of group member to remove
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
int
psRemoveHostGroupMember(char *groupName, char *memberName)
{
    int ret;
    char groupPropListName[MAXNAMELEN];
    char groupPropName[MAXNAMELEN];

    if (iPsExtendedMode == B_TRUE) {
        return iPsRemoveGroupMemberExt(STMF_HOST_GROUPS, groupName, memberName);
    }

    if ((ret = iPsGetActualGroupName(STMF_HOST_GROUPS, groupName, groupPropName))
        != STMF_PS_SUCCESS) {
        return (ret);
    }

    if (snprintf(groupPropListName, sizeof (groupPropListName), "%s-%s",
        groupPropName, STMF_MEMBER_LIST_SUFFIX) > sizeof (groupPropListName)) {
        syslog(LOG_ERR, "buffer overflow on property name %s", groupPropName);
        return (STMF_PS_ERROR);
    }

    return (iPsAddRemoveGroupMember(STMF_HOST_GROUPS, groupPropListName,
            memberName, REMOVE));
}

/*
 * psRemoveTargetGroupMember
 *
 * Remove a target port group member from an target port group,
 *
 * groupName - name of group from which the member is removed
 * memberName - name of group member to remove
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
int
psRemoveTargetGroupMember(char *groupName, char *memberName)
{
    int ret;
    char groupPropListName[MAXNAMELEN];
    char groupPropName[MAXNAMELEN];

    if (iPsExtendedMode == B_TRUE) {
        return iPsRemoveGroupMemberExt(STMF_TARGET_GROUPS, groupName,
                                       memberName);
    }

    if ((ret = iPsGetActualGroupName(STMF_TARGET_GROUPS, groupName,
                                     groupPropName)) != STMF_PS_SUCCESS) {
        return (ret);
    }

    if (snprintf(groupPropListName, sizeof (groupPropListName), "%s-%s",
        groupPropName, STMF_MEMBER_LIST_SUFFIX) > sizeof (groupPropListName)) {
        syslog(LOG_ERR, "buffer overflow on property name %s", groupPropName);
        return (STMF_PS_ERROR);
    }

    return (iPsAddRemoveGroupMember(STMF_TARGET_GROUPS, groupPropListName,
                                    memberName, REMOVE));
}

/*
 * psGetProviderData
 *
 * Retrieves an nvlist on a per provider basis
 *
 * providerName - property group name to use
 * nvl - nvlist to retrieve
 *
 */
int
psGetProviderData(char *providerName, nvlist_t **nvl, int providerType,
                  uint64_t *setToken)
{
	scf_handle_t	*handle = NULL;
	scf_service_t	*svc = NULL;
	scf_propertygroup_t	*pg = NULL;
	scf_property_t	*prop = NULL;
	scf_value_t	*value = NULL;
	uint64_t blockCnt = 0;
	ssize_t blockOffset = 0;
	ssize_t actualBlockSize = 0;
	char pgName[MAXPATHLEN];
	char dataPropertyName[STMF_PROVIDER_DATA_PROP_NAME_SIZE];
	char *nvlistEncoded = NULL;
	ssize_t nvlistEncodedSize = 0;
	boolean_t foundSetCnt = B_TRUE;
	int i;
	int ret = STMF_PS_SUCCESS;

	if (providerName == NULL || (providerType != STMF_LU_PROVIDER_TYPE
                                 && providerType != STMF_PORT_PROVIDER_TYPE)) {
		ret = STMF_PS_ERROR_INVALID_ARG;
		goto out;
	}

    if (iPsExtendedMode == B_TRUE) {
        return iPsGetProviderDataExt(providerName, nvl, providerType, setToken);
    }
	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	/*
	 * create the property group name
	 */
	(void) snprintf(pgName, sizeof (pgName), "%s%s", STMF_PROVIDER_DATA_PREFIX,
                    providerName);

	/*
	 * Allocate scf resources
	 */
	if (((pg = scf_pg_create(handle)) == NULL) ||
	    ((value = scf_value_create(handle)) == NULL) ||
	    ((prop = scf_property_create(handle)) == NULL)) {
		syslog(LOG_ERR, "scf alloc resource failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * Retrieve the existing property group.
	 */
	if (scf_service_get_pg(svc, pgName, pg) == -1) {
		if (scf_error() != SCF_ERROR_NOT_FOUND) {
			syslog(LOG_ERR, "get pg %s failed - %s", pgName,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		} else {
			ret = STMF_PS_ERROR_NOT_FOUND;
			goto out;
		}
	}

	/*
	 * Get the STMF_PROVIDER_DATA_PROP_COUNT property
	 */
	if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_COUNT,
	    prop) == -1) {
		syslog(LOG_ERR, "get property %s/%s failed - %s",
		    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * Get the STMF_PROVIDER_DATA_PROP_COUNT value
	 */
	if (scf_property_get_value(prop, value) == -1) {
		syslog(LOG_ERR, "get property value %s/%s failed - %s",
		    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * Now get the actual value from the value handle
	 */
	if (scf_value_get_count(value, &blockCnt) == -1) {
		syslog(LOG_ERR, "get integer value %s/%s failed - %s",
		    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/* Has the caller requested the token to be set? */
	if (setToken) {
		/*
		 * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT property
		 * If it doesn't exist, we assume it to be zero.
		 */
		*setToken = 0;
		if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_SET_COUNT, prop) == -1) {
			if (scf_error() == SCF_ERROR_NOT_FOUND) {
				foundSetCnt = B_FALSE;
			} else {
				syslog(LOG_ERR, "get property %s/%s "
				    "failed - %s", pgName,
				    STMF_PROVIDER_DATA_PROP_SET_COUNT,
				    scf_strerror(scf_error()));
				ret = STMF_PS_ERROR;
				goto out;
			}
		}

		if (foundSetCnt) {
			/*
			 * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT value
			 */
			if (scf_property_get_value(prop, value) == -1) {
				syslog(LOG_ERR,
				    "get property value %s/%s failed - %s",
				    pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
				    scf_strerror(scf_error()));
				ret = STMF_PS_ERROR;
				goto out;
			}

			/*
			 * Now get the actual value from the value handle
			 * and set the caller's token
			 */
			if (scf_value_get_count(value, setToken) == -1) {
				syslog(LOG_ERR,
				    "get integer value %s/%s failed - %s",
				    pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
				    scf_strerror(scf_error()));
				ret = STMF_PS_ERROR;
				goto out;
			}
		}
	}

	nvlistEncoded = (char *)calloc(1, blockCnt * STMF_PROVIDER_DATA_PROP_SIZE);
	if (nvlistEncoded == NULL) {
		syslog(LOG_ERR, "nvlistEncoded alloc failed");
		ret = STMF_PS_ERROR_NOMEM;
		goto out;
	}

	for (i = 0; i < blockCnt; i++) {
		bzero(dataPropertyName, sizeof (dataPropertyName));
		/*
		 * create the name to use for the property
		 */
		(void) snprintf(dataPropertyName, sizeof (dataPropertyName),
		    "%s-%d", STMF_PROVIDER_DATA_PROP_PREFIX, i);

		if (scf_pg_get_property(pg, dataPropertyName, prop) == -1) {
			syslog(LOG_ERR, "get property %s/%s failed - %s",
			    pgName, dataPropertyName,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		if (scf_property_get_value(prop, value) == -1) {
			syslog(LOG_ERR, "get property value %s/%s failed - %s",
			    pgName, dataPropertyName,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/*
		 * Set the data block offset
		 */
		blockOffset = STMF_PROVIDER_DATA_PROP_SIZE * i;
		actualBlockSize = scf_value_get_opaque(value,
		    &nvlistEncoded[blockOffset], STMF_PROVIDER_DATA_PROP_SIZE);
		if (actualBlockSize == -1) {
			syslog(LOG_ERR, "get opaque property value %s/%s "
			    "failed - %s", pgName, dataPropertyName,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
		nvlistEncodedSize += actualBlockSize;
	}

	if (nvlist_unpack(nvlistEncoded, nvlistEncodedSize, nvl, 0) != 0) {
		syslog(LOG_ERR, "unable to unpack nvlist");
		ret = STMF_PS_ERROR;
		goto out;
	}

out:
	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}
	if (prop != NULL) {
		scf_property_destroy(prop);
	}
	if (value != NULL) {
		scf_value_destroy(value);
	}
	if (nvlistEncoded != NULL) {
		free(nvlistEncoded);
	}

	return (ret);

}
/*
 * psGetProviderDataList
 *
 * Retrieves the list of providers that currently store persistent data
 *
 * providerList - pointer to a pointer to an stmfProviderList structure
 *                On success, this will contain the list of providers
 *                currently storing persistent data.
 */
int
psGetProviderDataList(stmfProviderList **providerList)
{
	scf_handle_t *handle = NULL;
	scf_service_t *svc = NULL;
	scf_propertygroup_t *pg = NULL;
	scf_property_t *prop = NULL;
	scf_value_t *value = NULL;
	scf_iter_t *pgIter = NULL;
	char buf[MAXNAMELEN];
	int providerCnt = 0;
	int64_t providerType;
	int i = 0, j;
	int ret = STMF_PS_SUCCESS;

    if (iPsExtendedMode == B_TRUE) {
        return iPsGetProviderDataListExt(providerList);
    }

	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	*providerList = NULL;

	/*
	 * Allocate scf resources
	 */
	if (((pg = scf_pg_create(handle)) == NULL) ||
	    ((value = scf_value_create(handle)) == NULL) ||
	    ((prop = scf_property_create(handle)) == NULL) ||
	    ((pgIter = scf_iter_create(handle)) == NULL)) {
		syslog(LOG_ERR, "scf alloc resource failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * pgIter is the iterator handle
	 */
	if (scf_iter_service_pgs(pgIter, svc) == -1) {
		syslog(LOG_ERR, "iter property groups failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	while (scf_iter_next_pg(pgIter, pg) == 1) {
		if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
			syslog(LOG_ERR, "get name failed - %s",
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}
		/*
		 * Only count LU property groups
		 */
		if (strncmp(buf, STMF_PROVIDER_DATA_PREFIX,
		    strlen(STMF_PROVIDER_DATA_PREFIX)) == 0) {
			providerCnt++;
		}
	}

	/*
	 * pgIter is the iterator handle
	 */
	if (scf_iter_service_pgs(pgIter, svc) == -1) {
		syslog(LOG_ERR, "iter property groups failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	*providerList = (stmfProviderList *)calloc(1,
	    sizeof (stmfProviderList) + providerCnt * sizeof (stmfProvider));
	if (*providerList == NULL) {
		ret = STMF_PS_ERROR_NOMEM;
		goto out;
	}

	/*
	 * it's possible for entries to be added/removed while we're retrieving
	 * the property groups. Just make sure we don't write beyond our
	 * allocated buffer by checking to ensure i < providerCnt.
	 */
	while ((scf_iter_next_pg(pgIter, pg) == 1) && (i < providerCnt)) {
		if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
			syslog(LOG_ERR, "get name failed - %s",
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}
		/*
		 * Only use provider data property groups
		 */
		if (strncmp(buf, STMF_PROVIDER_DATA_PREFIX,
		    strlen(STMF_PROVIDER_DATA_PREFIX)) != 0) {
			continue;
		}

		/*
		 * Get the STMF_PROVIDER_DATA_PROP_TYPE property
		 */
		if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_TYPE,
		    prop) == -1) {
			syslog(LOG_ERR, "get property %s/%s failed - %s",
			    buf, STMF_PROVIDER_DATA_PROP_TYPE,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}

		/*
		 * Get the STMF_PROVIDER_DATA_PROP_TYPE value
		 */
		if (scf_property_get_value(prop, value) == -1) {
			syslog(LOG_ERR, "get property value %s/%s failed - %s",
			    buf, STMF_PROVIDER_DATA_PROP_TYPE,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}

		/*
		 * Now get the actual value from the value handle
		 */
		if (scf_value_get_integer(value, &providerType) == -1) {
			syslog(LOG_ERR, "get integer value %s/%s failed - %s",
			    buf, STMF_PROVIDER_DATA_PROP_TYPE,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			break;
		}

		(*providerList)->provider[i].providerType = providerType;

		/* determine offset for copy of provider name */
		j = strlen(STMF_PROVIDER_DATA_PREFIX);

		/* copy provider name to caller's list */
		(void) strncpy((*providerList)->provider[i].name, buf + j,
		    sizeof ((*providerList)->provider[i].name));
		i++;
		(*providerList)->cnt++;
	}

	if (ret != STMF_PS_SUCCESS) {
		free(*providerList);
		goto out;
	}

out:
	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}
	if (value != NULL) {
		scf_value_destroy(value);
	}
	if (prop != NULL) {
		scf_property_destroy(prop);
	}
	if (pgIter != NULL) {
		scf_iter_destroy(pgIter);
	}

	return (ret);
}


/*
 * psSetProviderData
 *
 * Stores a packed nvlist on a per provider basis
 *
 * providerName - property group name to use
 * nvl - nvlist to store
 * providerType - type of provider (logical unit or port)
 *
 */
int
psSetProviderData(char *providerName, nvlist_t *nvl, int providerType, uint64_t *setToken)
{
	scf_handle_t	*handle = NULL;
	scf_service_t	*svc = NULL;
	scf_propertygroup_t	*pg = NULL;
	scf_property_t	*prop = NULL;
	scf_transaction_t *tran = NULL;
	/* represents arrays of entry and value pointers for scf */
	scf_transaction_entry_t	**addEntry = NULL;
	scf_transaction_entry_t	**deleteEntry = NULL;
	scf_value_t **addValue = NULL;

	/*
	 * These declarations are for known entry and value set/get
	 * operations
	 */
	scf_transaction_entry_t *entry1 = NULL;
	scf_transaction_entry_t *entry2 = NULL;
	scf_transaction_entry_t *entry3 = NULL;
	scf_transaction_entry_t *entry5 = NULL;
	scf_value_t *value1 = NULL;
	scf_value_t *value2 = NULL;
	scf_value_t *value3 = NULL;
	scf_value_t *value4 = NULL;
	scf_value_t *value5 = NULL;

	boolean_t newPg = B_FALSE;
	char pgName[MAXPATHLEN];
	char dataPropertyName[STMF_PROVIDER_DATA_PROP_NAME_SIZE];
	char *nvlistEncoded = NULL;
	size_t nvlistEncodedSize;
	size_t blockSize;
	int i, j = 0;
	int addEntryAlloc = 0, deleteEntryAlloc = 0, addValueAlloc = 0;
	int blockOffset;
	uint64_t oldBlockCnt = 0;
	uint64_t blockCnt = 0;
	uint64_t setCnt = 0;
	boolean_t foundSetCnt = B_TRUE;
	int ret = STMF_PS_SUCCESS;
	int commitRet;

	if (providerName == NULL || (providerType != STMF_LU_PROVIDER_TYPE &&
	    providerType != STMF_PORT_PROVIDER_TYPE)) {
		ret = STMF_PS_ERROR_INVALID_ARG;
		goto out;
	}

    if (iPsExtendedMode == B_TRUE) {
        ret = iPsSetProviderDataExt(providerName, nvl, providerType, setToken);
		return ret;
    }

	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	bzero(pgName, sizeof (pgName));
	/*
	 * create the property group name
	 */
	(void) snprintf(pgName, sizeof (pgName), "%s%s",
	    STMF_PROVIDER_DATA_PREFIX, providerName);

	/*
	 * Allocate scf resources
	 */
	if (((pg = scf_pg_create(handle)) == NULL) ||
	    ((entry1 = scf_entry_create(handle)) == NULL) ||
	    ((entry2 = scf_entry_create(handle)) == NULL) ||
	    ((entry3 = scf_entry_create(handle)) == NULL) ||
	    ((entry5 = scf_entry_create(handle)) == NULL) ||
	    ((value1 = scf_value_create(handle)) == NULL) ||
	    ((value2 = scf_value_create(handle)) == NULL) ||
	    ((value3 = scf_value_create(handle)) == NULL) ||
	    ((value4 = scf_value_create(handle)) == NULL) ||
	    ((value5 = scf_value_create(handle)) == NULL) ||
	    ((prop = scf_property_create(handle)) == NULL) ||
	    ((tran = scf_transaction_create(handle)) == NULL)) {
		syslog(LOG_ERR, "scf alloc resource failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/*
	 * Get the existing property group
	 */
	if (scf_service_get_pg(svc, pgName, pg) == -1) {
		if (scf_error() != SCF_ERROR_NOT_FOUND) {
			syslog(LOG_ERR, "get pg %s failed - %s",
			    pgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		} else {
			/*
			 * create the property group.
			 */
			if (scf_service_add_pg(svc, pgName,
			    SCF_GROUP_APPLICATION, 0, pg) == -1) {
				syslog(LOG_ERR, "add pg %s failed - %s",
				    pgName, scf_strerror(scf_error()));
				ret = STMF_PS_ERROR;
				goto out;
			}
			newPg = B_TRUE;
		}
	}

	/*
	 * Begin the transaction
	 */
	if (scf_transaction_start(tran, pg) == -1) {
		syslog(LOG_ERR, "start transaction for %s failed - %s",
		    pgName, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	if (!newPg) {
		/*
		 * Get the STMF_PROVIDER_DATA_PROP_COUNT property
		 */
		if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_COUNT,
		    prop) == -1) {
			syslog(LOG_ERR, "get property %s/%s failed - %s",
			    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/*
		 * Get the STMF_PROVIDER_DATA_PROP_COUNT value
		 */
		if (scf_property_get_value(prop, value4) == -1) {
			syslog(LOG_ERR, "get property value %s/%s failed - %s",
			    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/*
		 * Now get the actual value from the value handle
		 */
		if (scf_value_get_count(value4, &oldBlockCnt) == -1) {
			syslog(LOG_ERR, "get integer value %s/%s failed - %s",
			    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	}

	/*
	 * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT property
	 * If it doesn't exist, we'll create it later after successfully
	 * setting the data.
	 */
	if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_SET_COUNT,
	    prop) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND) {
			foundSetCnt = B_FALSE;
		} else {
			syslog(LOG_ERR, "get property %s/%s failed - %s",
			    pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	}

	if (foundSetCnt) {
		/*
		 * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT value
		 */
		if (scf_property_get_value(prop, value5) == -1) {
			syslog(LOG_ERR, "get property value %s/%s failed - %s",
			    pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/*
		 * Now get the actual value from the value handle
		 */
		if (scf_value_get_count(value5, &setCnt) == -1) {
			syslog(LOG_ERR, "get integer value %s/%s failed - %s",
			    pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/*
		 * Compare the setCnt prop to the caller's.
		 */
		if (setToken && (*setToken != setCnt)) {
			ret = STMF_PS_ERROR_PROV_DATA_STALE;
			goto out;
		}
	}

	setCnt++;

	/*
	 * prepare the list for writing
	 */
	if (nvlist_pack(nvl, &nvlistEncoded, &nvlistEncodedSize,
	    NV_ENCODE_XDR, 0) != 0) {
		syslog(LOG_ERR, "nvlist_pack for %s failed",
		    pgName);
		ret = STMF_PS_ERROR_NOMEM;
		goto out;
	}

	/* Determine how many chunks we need to write */
	blockCnt = nvlistEncodedSize/STMF_PROVIDER_DATA_PROP_SIZE;
	if (nvlistEncodedSize % STMF_PROVIDER_DATA_PROP_SIZE)
		blockCnt++;

	/* allocate entry and value resources for writing those chunks */
	addEntry = (scf_transaction_entry_t **)calloc(1, sizeof (*addEntry)
	    * blockCnt);
	if (addEntry == NULL) {
		syslog(LOG_ERR, "addEntry alloc for %s failed", pgName);
		ret = STMF_PS_ERROR_NOMEM;
		goto out;
	}

	addValue = (scf_value_t **)calloc(1, sizeof (*addValue)
	    * blockCnt);
	if (addValue == NULL) {
		syslog(LOG_ERR, "value alloc for %s failed", pgName);
		ret = STMF_PS_ERROR_NOMEM;
		goto out;
	}

	/*
	 * allocate entry delete resources for deleting anything existing
	 * that is more than the new block count. We could leave them around
	 * without suffering any ill effects but it will be cleaner to look at
	 * in smf tools if they are deleted.
	 */
	if (oldBlockCnt > blockCnt) {
		deleteEntry = (scf_transaction_entry_t **)calloc(1,
		    sizeof (*deleteEntry) * (oldBlockCnt - blockCnt));
		if (deleteEntry == NULL) {
			syslog(LOG_ERR, "deleteEntry alloc for %s failed",
			    pgName);
			ret = STMF_PS_ERROR_NOMEM;
			goto out;
		}
		deleteEntryAlloc = oldBlockCnt - blockCnt;
	}


	for (i = 0; i < blockCnt; i++) {
		/*
		 * Create the entry resource for the prop
		 */
		addEntry[i] = scf_entry_create(handle);
		if (addEntry[i] == NULL) {
			syslog(LOG_ERR, "scf value alloc for %s failed - %s",
			    pgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/* bump alloc count for addEntry allocation */
		addEntryAlloc++;

		/*
		 * create the name to use for the property
		 */
		(void) snprintf(dataPropertyName, sizeof (dataPropertyName),
		    "%s-%d", STMF_PROVIDER_DATA_PROP_PREFIX, i);

		/*
		 * Create the new property
		 */
		if (scf_transaction_property_new(tran, addEntry[i],
		    dataPropertyName, SCF_TYPE_OPAQUE) == -1) {
			if (scf_error() == SCF_ERROR_EXISTS) {
				if (scf_transaction_property_change(tran,
				    addEntry[i], dataPropertyName,
				    SCF_TYPE_OPAQUE) == -1) {
					syslog(LOG_ERR, "transaction property "
					    "change %s/%s failed - %s",
					    pgName, dataPropertyName,
					    scf_strerror(scf_error()));
					ret = STMF_PS_ERROR;
					goto out;
				}
			} else {
				syslog(LOG_ERR,
				    "transaction property new %s/%s "
				    "failed - %s", pgName, dataPropertyName,
				    scf_strerror(scf_error()));
				ret = STMF_PS_ERROR;
				goto out;
			}
		}
		/*
		 * Create the value resource for the prop
		 */
		addValue[i] = scf_value_create(handle);
		if (addValue[i] == NULL) {
			syslog(LOG_ERR, "scf value alloc for %s failed - %s",
			    pgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/* bump alloc count for addValue allocation */
		addValueAlloc++;

		/*
		 * Set the data block offset and size
		 */
		if ((STMF_PROVIDER_DATA_PROP_SIZE * (i + 1))
		    > nvlistEncodedSize) {
			blockSize = nvlistEncodedSize
			    - STMF_PROVIDER_DATA_PROP_SIZE * i;
		} else {
			blockSize = STMF_PROVIDER_DATA_PROP_SIZE;
		}

		blockOffset = STMF_PROVIDER_DATA_PROP_SIZE * i;
		if (scf_value_set_opaque(addValue[i],
		    &nvlistEncoded[blockOffset], blockSize) == -1) {
			syslog(LOG_ERR, "set value for %s failed - %s",
			    pgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/*
		 * Add the data block to the transaction entry
		 */
		if (scf_entry_add_value(addEntry[i], addValue[i]) == -1) {
			syslog(LOG_ERR, "add value for %s failed - %s",
			    pgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	}

	/*
	 * Now we need to delete any chunks (properties) that are no longer
	 * needed. Iterate through the rest of the chunks deleting each.
	 */
	for (i = blockCnt; i < oldBlockCnt; i++) {
		/*
		 * Create the entry resource for the prop
		 */
		deleteEntry[j] = scf_entry_create(handle);
		if (deleteEntry[j] == NULL) {
			syslog(LOG_ERR, "scf value alloc for %s failed - %s",
			    pgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		/*
		 * create the name to use for the property
		 */
		(void) snprintf(dataPropertyName, sizeof (dataPropertyName),
		    "%s-%d", STMF_PROVIDER_DATA_PROP_PREFIX, i);

		/*
		 * Delete the existing property
		 */
		if (scf_transaction_property_delete(tran, deleteEntry[j++],
		    dataPropertyName) == -1) {
			syslog(LOG_ERR, "delete property %s/%s failed - %s",
			    pgName, dataPropertyName,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	}

	if (newPg) {
		/*
		 * Ensure the read_authorization property is set
		 * for the group
		 */
		if (scf_transaction_property_new(tran, entry1,
		    "read_authorization", SCF_TYPE_ASTRING) == -1) {
			syslog(LOG_ERR, "transaction property %s/%s new "
			    "failed - %s", pgName, "read_authorization",
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		if (scf_value_set_astring(value1, STMF_SMF_READ_ATTR) == -1) {
			syslog(LOG_ERR, "set value %s/%s failed - %s",
			    pgName, "read_authorization",
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}

		if (scf_entry_add_value(entry1, value1) == -1) {
			syslog(LOG_ERR, "add value %s/%s failed - %s",
			    pgName, "read_authorization",
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	}

	/* create or change the count property */
	if (scf_transaction_property_new(tran, entry2,
	    STMF_PROVIDER_DATA_PROP_COUNT, SCF_TYPE_COUNT) == -1) {
		if (scf_error() == SCF_ERROR_EXISTS) {
			if (scf_transaction_property_change(tran, entry2,
			    STMF_PROVIDER_DATA_PROP_COUNT,
			    SCF_TYPE_COUNT) == -1) {
				syslog(LOG_ERR, "transaction property change "
				    "%s/%s failed - %s", pgName,
				    STMF_PROVIDER_DATA_PROP_COUNT,
				    scf_strerror(scf_error()));
				ret = STMF_PS_ERROR;
				goto out;
			}
		} else {
			syslog(LOG_ERR, "transaction property %s/%s new "
			    "failed - %s", pgName,
			    STMF_PROVIDER_DATA_PROP_COUNT,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	}

	scf_value_set_count(value2, blockCnt);

	if (scf_entry_add_value(entry2, value2) == -1) {
		syslog(LOG_ERR, "add value %s/%s failed - %s",
		    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/* create or change the set count property */
	if (scf_transaction_property_new(tran, entry5,
	    STMF_PROVIDER_DATA_PROP_SET_COUNT, SCF_TYPE_COUNT) == -1) {
		if (scf_error() == SCF_ERROR_EXISTS) {
			if (scf_transaction_property_change(tran, entry5,
			    STMF_PROVIDER_DATA_PROP_SET_COUNT,
			    SCF_TYPE_COUNT) == -1) {
				syslog(LOG_ERR,
				    "transaction property change %s/%s "
				    "failed - %s", pgName,
				    STMF_PROVIDER_DATA_PROP_SET_COUNT,
				    scf_strerror(scf_error()));
				ret = STMF_PS_ERROR;
				goto out;
			}
		} else {
			syslog(LOG_ERR, "transaction property new %s/%s "
			    "failed - %s", pgName,
			    STMF_PROVIDER_DATA_PROP_SET_COUNT,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	}



	scf_value_set_count(value5, setCnt);

	if (scf_entry_add_value(entry5, value5) == -1) {
		syslog(LOG_ERR, "add value %s/%s failed - %s",
		    pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/* create or change the provider type property */
	if (scf_transaction_property_new(tran, entry3,
	    STMF_PROVIDER_DATA_PROP_TYPE, SCF_TYPE_INTEGER) == -1) {
		if (scf_error() == SCF_ERROR_EXISTS) {
			if (scf_transaction_property_change(tran, entry3,
			    STMF_PROVIDER_DATA_PROP_TYPE,
			    SCF_TYPE_INTEGER) == -1) {
				syslog(LOG_ERR,
				    "transaction property change %s/%s "
				    "failed - %s", pgName,
				    STMF_PROVIDER_DATA_PROP_TYPE,
				    scf_strerror(scf_error()));
				ret = STMF_PS_ERROR;
				goto out;
			}
		} else {
			syslog(LOG_ERR, "transaction property new %s/%s "
			    "failed - %s", pgName, STMF_PROVIDER_DATA_PROP_TYPE,
			    scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
			goto out;
		}
	}

	switch (providerType) {
		case STMF_PORT_PROVIDER_TYPE:
		case STMF_LU_PROVIDER_TYPE:
			scf_value_set_integer(value3, providerType);
			break;
		default:
			ret = STMF_PS_ERROR;
			goto out;
	}

	if (scf_entry_add_value(entry3, value3) == -1) {
		syslog(LOG_ERR, "add value %s/%s failed - %s", pgName,
		    STMF_PROVIDER_DATA_PROP_TYPE, scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}


	if ((commitRet = scf_transaction_commit(tran)) != 1) {
		syslog(LOG_ERR, "transaction commit for %s failed - %s",
		    pgName, scf_strerror(scf_error()));
		if (commitRet == 0) {
			ret = STMF_PS_ERROR_BUSY;
		} else {
			ret = STMF_PS_ERROR;
		}
		goto out;
	}

	/* pass the new token back to the caller if requested */
	if (ret == STMF_PS_SUCCESS && setToken) {
		*setToken = setCnt;
	}

out:
	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}
	if (prop != NULL) {
		scf_property_destroy(prop);
	}
	if (tran != NULL) {
		scf_transaction_destroy(tran);
	}
	for (i = 0; i < addEntryAlloc; i++) {
		scf_entry_destroy(addEntry[i]);
	}
	for (i = 0; i < addValueAlloc; i++) {
		scf_value_destroy(addValue[i]);
	}
	free(addValue);
	free(addEntry);
	for (i = 0; i < deleteEntryAlloc; i++) {
		scf_entry_destroy(deleteEntry[i]);
	}
	free(deleteEntry);
	if (entry1 != NULL) {
		scf_entry_destroy(entry1);
	}
	if (entry2 != NULL) {
		scf_entry_destroy(entry2);
	}
	if (entry3 != NULL) {
		scf_entry_destroy(entry3);
	}
	if (entry5 != NULL) {
		scf_entry_destroy(entry5);
	}
	if (value1 != NULL) {
		scf_value_destroy(value1);
	}
	if (value2 != NULL) {
		scf_value_destroy(value2);
	}
	if (value3 != NULL) {
		scf_value_destroy(value3);
	}
	if (value4 != NULL) {
		scf_value_destroy(value4);
	}
	if (value5 != NULL) {
		scf_value_destroy(value5);
	}
	if (nvlistEncoded != NULL) {
		free(nvlistEncoded);
	}

	return (ret);
}

/*
 * psGetViewEntry
 *
 * Purpose: Get a single view entry based on the logical unit identifier and
 *          view entry index
 *
 * lu - logical unit identifier
 * viewEntryIndex - index of view entry
 * ve - caller allocated stmfViewEntry structure. On success, this will
 *      contain the retrieved view entry
 */
int
psGetViewEntry(stmfGuid *lu, uint32_t viewEntryIndex, stmfViewEntry *ve)
{
	scf_handle_t	*handle = NULL;
	scf_service_t	*svc = NULL;
	scf_propertygroup_t	*pg = NULL;
	char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
	char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
	char luPgName[LOGICAL_UNIT_PG_SIZE];
	int ret = STMF_PS_SUCCESS;

	if (iPsExtendedMode == B_TRUE) {
		return iPsGetViewEntryExt(lu, viewEntryIndex, ve);
	}
	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	pg = scf_pg_create(handle);
	if (pg == NULL) {
		syslog(LOG_ERR, "scf pg alloc failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/* Convert to ASCII uppercase hexadecimal string */
	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
	    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
	    lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
	    lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
	    lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
	    lu->guid[14], lu->guid[15]);

	(void) snprintf(luPgName, sizeof (luPgName), "%s-%s",
	    STMF_LU_PREFIX, guidAsciiBuf);

	/*
	 * Format of view entry property group name:
	 *	VE-<view_entry_index>-<lu_name>
	 */
	(void) snprintf(viewEntryPgName, sizeof (viewEntryPgName),
	    "%s-%d-%s", STMF_VE_PREFIX, viewEntryIndex, guidAsciiBuf);

	if (scf_service_get_pg(svc, viewEntryPgName, pg) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND) {
			ret = STMF_PS_ERROR_NOT_FOUND;
		} else {
			syslog(LOG_ERR, "get pg %s failed - %s",
			    viewEntryPgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
		}
		goto out;
	}


	if ((ret = iPsGetViewEntry(viewEntryPgName, ve)) != STMF_PS_SUCCESS) {
		ret = STMF_PS_ERROR;
		goto out;
	}

out:
	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}

	return (ret);
}

/*
 * psRemoveViewEntry
 *
 * Remove a view entry
 *
 * luGuid - identifier of logical unit from which to remove view entry
 * viewEntryIndex - view entry name to remove
 *
 * returns:
 *  STMF_PS_SUCCESS on success
 *  STMF_PS_ERROR_* on failure
 */
int
psRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex)
{
	scf_handle_t	*handle = NULL;
	scf_service_t	*svc = NULL;
	scf_propertygroup_t	*pg = NULL;
	char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
	char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
	char luPgName[LOGICAL_UNIT_PG_SIZE];
	int ret = STMF_PS_SUCCESS;
	sigset_t sigmaskRestore;

	/* grab the signal hold lock */
	(void) pthread_mutex_lock(&sigSetLock);

	/*
	 * hold signals until we're done
	 */
	if (holdSignal(&sigmaskRestore) != 0) {
		(void) pthread_mutex_unlock(&sigSetLock);
		return (STMF_PS_ERROR);
	}

    if (iPsExtendedMode == B_TRUE) {
        ret = iPsRemoveViewEntryExt(lu, viewEntryIndex);
        goto out;
    }
	ret = iPsInit(&handle, &svc);
	if (ret != STMF_PS_SUCCESS) {
		goto out;
	}

	pg = scf_pg_create(handle);
	if (pg == NULL) {
		syslog(LOG_ERR, "scf pg alloc failed - %s",
		    scf_strerror(scf_error()));
		ret = STMF_PS_ERROR;
		goto out;
	}

	/* Convert to ASCII uppercase hexadecimal string */
	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
	    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
	    lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
	    lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
	    lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
	    lu->guid[14], lu->guid[15]);

	(void) snprintf(luPgName, sizeof (luPgName), "%s-%s",
	    STMF_LU_PREFIX, guidAsciiBuf);

	/*
	 * Format of view entry property group name:
	 *	VE-<view_entry_index>-<lu_name>
	 */
	(void) snprintf(viewEntryPgName, sizeof (viewEntryPgName),
	    "%s-%d-%s", STMF_VE_PREFIX, viewEntryIndex, guidAsciiBuf);

	if (scf_service_get_pg(svc, viewEntryPgName, pg) == -1) {
		if (scf_error() == SCF_ERROR_NOT_FOUND) {
			ret = STMF_PS_ERROR_NOT_FOUND;
		} else {
			syslog(LOG_ERR, "get pg %s failed - %s",
			    viewEntryPgName, scf_strerror(scf_error()));
			ret = STMF_PS_ERROR;
		}
		goto out;
	}

	/*
	 * update the logical unit property group to remove
	 * the view entry and update the view entry count
	 * If it fails, we won't delete the property group so that
	 * we maintain consistency.
	 */
	if ((ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName,
	    REMOVE)) != STMF_PS_SUCCESS) {
		goto out;
	}

	/*
	 * Delete the view entry. If this fails, we should try to add
	 * the logical unit view entry property group back otherwise
	 * we're inconsistent.
	 */
	if (scf_pg_delete(pg) == -1) {
		syslog(LOG_ERR, "delete pg %s failed - %s", viewEntryPgName,
		    scf_strerror(scf_error()));
		if ((ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName,
		    ADD)) != STMF_PS_SUCCESS) {
			syslog(LOG_ERR, "add of view entry %s failed, possible"
			    "inconsistency - %s", viewEntryPgName,
			    scf_strerror(scf_error()));
		}
		ret = STMF_PS_ERROR;
		goto out;
	}

out:
	/*
	 * Okay, we're done. Release the signals
	 */
	if (releaseSignal(&sigmaskRestore) != 0) {
		/*
		 * Don't set this as an STMF_PS_ERROR_*. We succeeded
		 * the requested operation. But we do need to log it.
		 */
		syslog(LOG_ERR, "Unable to release one or more signals - %s",
		    strerror(errno));
	}

	/*
	 * Free resources
	 */
	if (handle != NULL) {
		scf_handle_destroy(handle);
	}
	if (svc != NULL) {
		scf_service_destroy(svc);
	}
	if (pg != NULL) {
		scf_pg_destroy(pg);
	}

	/* release the signal hold lock */
	(void) pthread_mutex_unlock(&sigSetLock);

	return (ret);
}



/*
 * holdSignal
 *
 * Hold SIGINT, SIGTERM, SIGQUIT until further notice.
 *
 * Saves old signal mask on a per thread basis
 * and saves action for the process.
 *
 * Installs action for above signals.
 *
 * locks held: sigSetLock
 *
 * returns:
 *  0 on success
 *  non-zero otherwise
 */
static int
holdSignal(sigset_t *sigmaskRestore)
{
	struct sigaction act;
	sigset_t sigmask;

	/*
	 * Return existing signal mask for this thread
	 */
	if (pthread_sigmask(0, NULL, sigmaskRestore) != 0) {
		return (1);
	}

	(void) sigemptyset(&act.sa_mask);
	act.sa_handler = sigHandler;
	act.sa_flags = 0;

	/*
	 * Have we set the actions for the signals we want to catch?
	 */
	if (!actionSet) {
		if (sigaction(SIGQUIT, &act, &currentActionQuit) != 0) {
			return (1);
		}

		if (sigaction(SIGINT, &act, &currentActionInt) != 0) {
			return (1);
		}

		if (sigaction(SIGTERM, &act, &currentActionTerm) != 0) {
			return (1);
		}

		actionSet = B_TRUE;
	}

	/*
	 * We still need to change the mask for the current thread
	 */
	if (sigfillset(&sigmask) != 0) {
		return (1);
	}

	(void) sigdelset(&sigmask, SIGQUIT);

	(void) sigdelset(&sigmask, SIGINT);

	(void) sigdelset(&sigmask, SIGTERM);

	if (pthread_sigmask(SIG_SETMASK, &sigmask, NULL) != 0) {
		return (1);
	}

	return (0);
}

/*
 * releaseSignal
 *
 * Re-install the original signal mask and signal actions
 *
 * Also, raise any signals that were caught during the hold period and clear
 * the signal from the caught set (signalsCaught).
 *
 * locks held: sigSetLock
 *
 * Returns
 *  0 on success
 *  non-zero otherwise
 */
static int
releaseSignal(sigset_t *sigmaskRestore)
{
	int ret = 0;

	if (sigaction(SIGQUIT, &currentActionQuit, NULL) != 0) {
		ret = 1;
	}

	if (sigaction(SIGINT, &currentActionInt, NULL) != 0) {
		ret = 1;
	}

	if (sigaction(SIGTERM, &currentActionTerm, NULL) != 0) {
		ret = 1;
	}

	actionSet = B_FALSE;

	/*
	 * Restore previous signal mask for this thread
	 */
	if (pthread_sigmask(SIG_SETMASK, sigmaskRestore, NULL) != 0) {
		syslog(LOG_ERR, "Unable to restore sigmask");
	}

	/*
	 * Now raise signals that were raised while we were held
	 */
	if (sigismember(&signalsCaught, SIGTERM)) {
		(void) sigdelset(&signalsCaught, SIGTERM);
		(void) raise(SIGTERM);
	}

	if (sigismember(&signalsCaught, SIGINT)) {
		(void) sigdelset(&signalsCaught, SIGINT);
		(void) raise(SIGINT);
	}

	if (sigismember(&signalsCaught, SIGQUIT)) {
		(void) sigdelset(&signalsCaught, SIGQUIT);
		(void) raise(SIGQUIT);
	}

	return (ret);
}

#ifdef	__dilos__
char *
stmfServiceName(char *buf, size_t size)
{
	static const char	*file = "/etc/default/store-stmf-service";
	FILE		*f;
	struct stat	fs;
	char		*ret = NULL;
	size_t		len;

	f = fopen(file, "r");
	if (f != NULL) {
		if ((fstat(fileno(f), &fs) == 0) &&
			S_ISREG(fs.st_mode) && (fs.st_size > 0)) {
			len = fread(buf, sizeof(*buf), size, f);
			if (len > 0) {
				if (len == size)
					len--;
				buf[len] = '\0';
				ret = strchr(buf, '\n');
				if (ret != NULL)
					*ret = '\0';
				ret = strchr(buf, '\r');
				if (ret != NULL)
					*ret = '\0';
				ret = buf;
			}
		}
		fclose(f);
	}

	return (ret);
}
#endif	/* __dilos__ */
